diff --git a/.gitignore b/.gitignore index b757c53f1..9f2cba3bf 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ CMakeLists.txt.user .cproject .project .settings/ +.directory diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp index 5e580b6e1..d334a7f63 100644 --- a/apps/opencs/model/filter/parser.cpp +++ b/apps/opencs/model/filter/parser.cpp @@ -8,6 +8,8 @@ #include #include "../world/columns.hpp" +#include "../world/data.hpp" +#include "../world/idcollection.hpp" #include "booleannode.hpp" #include "ornode.hpp" @@ -31,6 +33,7 @@ namespace CSMFilter Type_OpenSquare, Type_CloseSquare, Type_Comma, + Type_OneShot, Type_Keyword_True, ///< \attention Keyword enums must be arranged continuously. Type_Keyword_False, Type_Keyword_And, @@ -44,7 +47,7 @@ namespace CSMFilter std::string mString; double mNumber; - Token (Type type); + Token (Type type = Type_None); Token (const std::string& string); @@ -89,7 +92,7 @@ CSMFilter::Token CSMFilter::Parser::getStringToken() { char c = mInput[mIndex]; - if (std::isalpha (c) || c=='_' || (!string.empty() && std::isdigit (c)) || c=='"' || + if (std::isalpha (c) || c==':' || c=='_' || (!string.empty() && std::isdigit (c)) || c=='"' || (!string.empty() && string[0]=='"')) string += c; else @@ -171,14 +174,14 @@ CSMFilter::Token CSMFilter::Parser::checkKeywords (const Token& token) { "true", "false", "and", "or", "not", - "text", "value", + "string", "value", 0 }; std::string string = Misc::StringUtils::lowerCase (token.mString); for (int i=0; sKeywords[i]; ++i) - if (sKeywords[i]==string) + if (sKeywords[i]==string || (string.size()==1 && sKeywords[i][0]==string[0])) return Token (static_cast (i+Token::Type_Keyword_True)); return token; @@ -208,9 +211,10 @@ CSMFilter::Token CSMFilter::Parser::getNextToken() case '[': ++mIndex; return Token (Token::Type_OpenSquare); case ']': ++mIndex; return Token (Token::Type_CloseSquare); case ',': ++mIndex; return Token (Token::Type_Comma); + case '!': ++mIndex; return Token (Token::Type_OneShot); } - if (c=='"' || c=='_' || std::isalpha (c)) + if (c=='"' || c=='_' || std::isalpha (c) || c==':') return getStringToken(); if (c=='-' || c=='.' || std::isdigit (c)) @@ -220,54 +224,58 @@ CSMFilter::Token CSMFilter::Parser::getNextToken() return Token (Token::Type_None); } -boost::shared_ptr CSMFilter::Parser::parseImp (bool allowEmpty) +boost::shared_ptr CSMFilter::Parser::parseImp (bool allowEmpty, bool ignoreOneShot) { if (Token token = getNextToken()) { - switch (token.mType) - { - case Token::Type_Keyword_True: + if (token==Token (Token::Type_OneShot)) + token = getNextToken(); - return boost::shared_ptr (new BooleanNode (true)); - - case Token::Type_Keyword_False: - - return boost::shared_ptr (new BooleanNode (false)); - - case Token::Type_Keyword_And: - case Token::Type_Keyword_Or: - - return parseNAry (token); - - case Token::Type_Keyword_Not: + if (token) + switch (token.mType) { - boost::shared_ptr node = parseImp(); + case Token::Type_Keyword_True: + + return boost::shared_ptr (new BooleanNode (true)); + + case Token::Type_Keyword_False: + + return boost::shared_ptr (new BooleanNode (false)); + + case Token::Type_Keyword_And: + case Token::Type_Keyword_Or: + + return parseNAry (token); + + case Token::Type_Keyword_Not: + { + boost::shared_ptr node = parseImp(); + + if (mError) + return boost::shared_ptr(); + + return boost::shared_ptr (new NotNode (node)); + } + + case Token::Type_Keyword_Text: + + return parseText(); + + case Token::Type_Keyword_Value: + + return parseValue(); + + case Token::Type_EOS: + + if (!allowEmpty) + error(); - if (mError) return boost::shared_ptr(); - return boost::shared_ptr (new NotNode (node)); - } + default: - case Token::Type_Keyword_Text: - - return parseText(); - - case Token::Type_Keyword_Value: - - return parseValue(); - - case Token::Type_EOS: - - if (!allowEmpty) error(); - - return boost::shared_ptr(); - - default: - - error(); - } + } } return boost::shared_ptr(); @@ -506,9 +514,10 @@ void CSMFilter::Parser::error() mError = true; } -CSMFilter::Parser::Parser() : mIndex (0), mError (false) {} +CSMFilter::Parser::Parser (const CSMWorld::Data& data) +: mIndex (0), mError (false), mData (data) {} -bool CSMFilter::Parser::parse (const std::string& filter) +bool CSMFilter::Parser::parse (const std::string& filter, bool allowPredefined) { // reset mFilter.reset(); @@ -516,23 +525,65 @@ bool CSMFilter::Parser::parse (const std::string& filter) mInput = filter; mIndex = 0; - boost::shared_ptr node = parseImp (true); + Token token; - if (mError) - return false; + if (allowPredefined) + token = getNextToken(); - if (getNextToken()!=Token (Token::Type_EOS)) - return false; + if (!allowPredefined || token==Token (Token::Type_OneShot)) + { + boost::shared_ptr node = parseImp (true, token!=Token (Token::Type_OneShot)); - if (node) - mFilter = node; + if (mError) + return false; + + if (getNextToken()!=Token (Token::Type_EOS)) + { + error(); + return false; + } + + if (node) + mFilter = node; + else + { + // Empty filter string equals to filter "true". + mFilter.reset (new BooleanNode (true)); + } + + return true; + } + else if (token.mType==Token::Type_String && allowPredefined) + { + if (getNextToken()!=Token (Token::Type_EOS)) + { + error(); + return false; + } + + int index = mData.getFilters().searchId (token.mString); + + if (index==-1) + { + error(); + return false; + } + + const CSMWorld::Record& record = mData.getFilters().getRecord (index); + + if (record.isDeleted()) + { + error(); + return false; + } + + return parse (record.get().mFilter, false); + } else { - // Empty filter string equals to filter "true". - mFilter.reset (new BooleanNode (true)); + error(); + return false; } - - return true; } boost::shared_ptr CSMFilter::Parser::getFilter() const diff --git a/apps/opencs/model/filter/parser.hpp b/apps/opencs/model/filter/parser.hpp index 1600992b7..5700102cf 100644 --- a/apps/opencs/model/filter/parser.hpp +++ b/apps/opencs/model/filter/parser.hpp @@ -5,6 +5,11 @@ #include "node.hpp" +namespace CSMWorld +{ + class Data; +} + namespace CSMFilter { struct Token; @@ -15,6 +20,7 @@ namespace CSMFilter std::string mInput; int mIndex; bool mError; + const CSMWorld::Data& mData; Token getStringToken(); @@ -25,7 +31,7 @@ namespace CSMFilter Token checkKeywords (const Token& token); ///< Turn string token into keyword token, if possible. - boost::shared_ptr parseImp (bool allowEmpty = false); + boost::shared_ptr parseImp (bool allowEmpty = false, bool ignoreOneShot = false); ///< Will return a null-pointer, if there is nothing more to parse. boost::shared_ptr parseNAry (const Token& keyword); @@ -38,9 +44,9 @@ namespace CSMFilter public: - Parser(); + Parser (const CSMWorld::Data& data); - bool parse (const std::string& filter); + bool parse (const std::string& filter, bool allowPredefined = true); ///< Discards any previous calls to parse /// /// \return Success? diff --git a/apps/opencs/model/world/cell.cpp b/apps/opencs/model/world/cell.cpp index fc367d1cc..cd58fca1e 100644 --- a/apps/opencs/model/world/cell.cpp +++ b/apps/opencs/model/world/cell.cpp @@ -7,7 +7,7 @@ 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 + ESM::Cell::load (esm, false); if (!(mData.mFlags & Interior)) { diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 526c07815..6cf31d0a4 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -236,14 +236,15 @@ namespace CSMWorld if (iter->second>=index+count) { iter->second -= count; + ++iter; } else { mIndex.erase (iter++); } } - - ++iter; + else + ++iter; } } diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 6c31fddf3..1a2bf9df1 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -1191,6 +1191,31 @@ namespace CSMWorld return true; } }; + + template + struct FilterColumn : public Column + { + FilterColumn() : Column (Columns::ColumnId_Filter, ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mFilter.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mFilter = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index f6eb8fe34..b20632258 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -144,6 +144,7 @@ namespace CSMWorld { ColumnId_MaxThrust, "Max Thrust" }, { ColumnId_Magical, "Magical" }, { ColumnId_Silver, "Silver" }, + { ColumnId_Filter, "Filter" }, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 28da60e93..9a39e1678 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -138,6 +138,7 @@ namespace CSMWorld ColumnId_MaxThrust = 106, ColumnId_Magical = 107, ColumnId_Silver = 108, + ColumnId_Filter = 109, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 43ecaca63..f6f421c6a 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -69,7 +69,9 @@ CSMWorld::RevertCommand::~RevertCommand() void CSMWorld::RevertCommand::redo() { - QModelIndex index = mModel.getModelIndex (mId, 1); + int column = mModel.findColumnIndex (Columns::ColumnId_Modification); + + QModelIndex index = mModel.getModelIndex (mId, column); RecordBase::State state = static_cast (mModel.data (index).toInt()); if (state==RecordBase::State_ModifiedOnly) @@ -102,7 +104,9 @@ CSMWorld::DeleteCommand::~DeleteCommand() void CSMWorld::DeleteCommand::redo() { - QModelIndex index = mModel.getModelIndex (mId, 1); + int column = mModel.findColumnIndex (Columns::ColumnId_Modification); + + QModelIndex index = mModel.getModelIndex (mId, column); RecordBase::State state = static_cast (mModel.data (index).toInt()); if (state==RecordBase::State_ModifiedOnly) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 4a5dcb38f..fbdbb4413 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -150,6 +150,7 @@ CSMWorld::Data::Data() : mRefs (mCells) mFilters.addColumn (new StringIdColumn); mFilters.addColumn (new RecordStateColumn); + mFilters.addColumn (new FilterColumn); mFilters.addColumn (new DescriptionColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); @@ -316,6 +317,16 @@ CSMWorld::RefCollection& CSMWorld::Data::getReferences() return mRefs; } +const CSMWorld::IdCollection& CSMWorld::Data::getFilters() const +{ + return mFilters; +} + +CSMWorld::IdCollection& CSMWorld::Data::getFilters() +{ + return mFilters; +} + 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 aebdd6ecd..2f8a2117e 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -119,6 +119,10 @@ namespace CSMWorld RefCollection& getReferences(); + const IdCollection& getFilters() const; + + IdCollection& getFilters(); + 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/ref.cpp b/apps/opencs/model/world/ref.cpp index e5e948928..af363bafb 100644 --- a/apps/opencs/model/world/ref.cpp +++ b/apps/opencs/model/world/ref.cpp @@ -8,8 +8,6 @@ void CSMWorld::CellRef::load (ESM::ESMReader &esm, Cell& cell, const std::string mId = id; mCellId = cell.mId; - cell.getNextRef (esm, *this); - if (!mDeleted) cell.addRef (mId); } \ No newline at end of file diff --git a/apps/opencs/view/filter/editwidget.cpp b/apps/opencs/view/filter/editwidget.cpp index b691a5e16..708d45032 100644 --- a/apps/opencs/view/filter/editwidget.cpp +++ b/apps/opencs/view/filter/editwidget.cpp @@ -1,11 +1,27 @@ #include "editwidget.hpp" -CSVFilter::EditWidget::EditWidget (QWidget *parent) -: QLineEdit (parent) +#include + +#include "../../model/world/data.hpp" + +CSVFilter::EditWidget::EditWidget (CSMWorld::Data& data, QWidget *parent) +: QLineEdit (parent), mParser (data) { mPalette = palette(); connect (this, SIGNAL (textChanged (const QString&)), this, SLOT (textChanged (const QString&))); + + QAbstractItemModel *model = data.getTableModel (CSMWorld::UniversalId::Type_Filters); + + connect (model, SIGNAL (dataChanged (const QModelIndex &, const QModelIndex&)), + this, SLOT (filterDataChanged (const QModelIndex &, const QModelIndex&)), + Qt::QueuedConnection); + connect (model, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), + this, SLOT (filterRowsRemoved (const QModelIndex&, int, int)), + Qt::QueuedConnection); + connect (model, SIGNAL (rowsInserted (const QModelIndex&, int, int)), + this, SLOT (filterRowsInserted (const QModelIndex&, int, int)), + Qt::QueuedConnection); } void CSVFilter::EditWidget::textChanged (const QString& text) @@ -23,4 +39,20 @@ void CSVFilter::EditWidget::textChanged (const QString& text) /// \todo improve error reporting; mark only the faulty part } -} \ No newline at end of file +} + +void CSVFilter::EditWidget::filterDataChanged (const QModelIndex& topLeft, + const QModelIndex& bottomRight) +{ + textChanged (text()); +} + +void CSVFilter::EditWidget::filterRowsRemoved (const QModelIndex& parent, int start, int end) +{ + textChanged (text()); +} + +void CSVFilter::EditWidget::filterRowsInserted (const QModelIndex& parent, int start, int end) +{ + textChanged (text()); +} diff --git a/apps/opencs/view/filter/editwidget.hpp b/apps/opencs/view/filter/editwidget.hpp index 76b484de9..31904e624 100644 --- a/apps/opencs/view/filter/editwidget.hpp +++ b/apps/opencs/view/filter/editwidget.hpp @@ -9,6 +9,13 @@ #include "../../model/filter/parser.hpp" #include "../../model/filter/node.hpp" +class QModelIndex; + +namespace CSMWorld +{ + class Data; +} + namespace CSVFilter { class EditWidget : public QLineEdit @@ -20,7 +27,7 @@ namespace CSVFilter public: - EditWidget (QWidget *parent = 0); + EditWidget (CSMWorld::Data& data, QWidget *parent = 0); signals: @@ -29,6 +36,12 @@ namespace CSVFilter private slots: void textChanged (const QString& text); + + void filterDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + + void filterRowsRemoved (const QModelIndex& parent, int start, int end); + + void filterRowsInserted (const QModelIndex& parent, int start, int end); }; } diff --git a/apps/opencs/view/filter/filterbox.cpp b/apps/opencs/view/filter/filterbox.cpp index 495abf871..273170884 100644 --- a/apps/opencs/view/filter/filterbox.cpp +++ b/apps/opencs/view/filter/filterbox.cpp @@ -5,14 +5,14 @@ #include "recordfilterbox.hpp" -CSVFilter::FilterBox::FilterBox (QWidget *parent) +CSVFilter::FilterBox::FilterBox (CSMWorld::Data& data, QWidget *parent) : QWidget (parent) { QHBoxLayout *layout = new QHBoxLayout (this); layout->setContentsMargins (0, 0, 0, 0); - RecordFilterBox *recordFilterBox = new RecordFilterBox (this); + RecordFilterBox *recordFilterBox = new RecordFilterBox (data, this); layout->addWidget (recordFilterBox); diff --git a/apps/opencs/view/filter/filterbox.hpp b/apps/opencs/view/filter/filterbox.hpp index d3806876d..2524fa0a3 100644 --- a/apps/opencs/view/filter/filterbox.hpp +++ b/apps/opencs/view/filter/filterbox.hpp @@ -5,6 +5,11 @@ #include "../../model/filter/node.hpp" +namespace CSMWorld +{ + class Data; +} + namespace CSVFilter { class FilterBox : public QWidget @@ -13,7 +18,7 @@ namespace CSVFilter public: - FilterBox (QWidget *parent = 0); + FilterBox (CSMWorld::Data& data, QWidget *parent = 0); signals: diff --git a/apps/opencs/view/filter/recordfilterbox.cpp b/apps/opencs/view/filter/recordfilterbox.cpp index 3b5f73f47..c405177b0 100644 --- a/apps/opencs/view/filter/recordfilterbox.cpp +++ b/apps/opencs/view/filter/recordfilterbox.cpp @@ -6,7 +6,7 @@ #include "editwidget.hpp" -CSVFilter::RecordFilterBox::RecordFilterBox (QWidget *parent) +CSVFilter::RecordFilterBox::RecordFilterBox (CSMWorld::Data& data, QWidget *parent) : QWidget (parent) { QHBoxLayout *layout = new QHBoxLayout (this); @@ -15,7 +15,7 @@ CSVFilter::RecordFilterBox::RecordFilterBox (QWidget *parent) layout->addWidget (new QLabel ("Record Filter", this)); - EditWidget *editWidget = new EditWidget (this); + EditWidget *editWidget = new EditWidget (data, this); layout->addWidget (editWidget); diff --git a/apps/opencs/view/filter/recordfilterbox.hpp b/apps/opencs/view/filter/recordfilterbox.hpp index 64c1848a8..057d69518 100644 --- a/apps/opencs/view/filter/recordfilterbox.hpp +++ b/apps/opencs/view/filter/recordfilterbox.hpp @@ -9,6 +9,11 @@ #include "../../model/filter/node.hpp" +namespace CSMWorld +{ + class Data; +} + namespace CSVFilter { class RecordFilterBox : public QWidget @@ -17,7 +22,7 @@ namespace CSVFilter public: - RecordFilterBox (QWidget *parent = 0); + RecordFilterBox (CSMWorld::Data& data, QWidget *parent = 0); signals: diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index a43ae2dac..1e05fbf51 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -25,7 +25,7 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D layout->insertWidget (0, mTable = new Table (id, document.getData(), document.getUndoStack(), mBottom->canCreateAndDelete()), 2); - CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (this); + CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this); layout->insertWidget (0, filterBox); diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 62a15fbf9..a2eccbaf9 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -123,6 +123,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch); MWBase::Environment::get().getWindowManager()->onFrame(frametime); + MWBase::Environment::get().getWindowManager()->update(); } catch (const std::exception& e) { @@ -385,26 +386,39 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) loadBSA(); + + // Create input and UI first to set up a bootstrapping environment for + // showing a loading screen and keeping the window responsive while doing so + + std::string keybinderUser = (mCfgMgr.getUserPath() / "input.xml").string(); + bool keybinderUserExists = boost::filesystem::exists(keybinderUser); + MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists); + mEnvironment.setInputManager (input); + + MWGui::WindowManager* window = new MWGui::WindowManager( + mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), + mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding); + mEnvironment.setWindowManager (window); + if (mNewGame) + mEnvironment.getWindowManager()->setNewGame(true); + // Create the world mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins, mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap, mActivationDistanceOverride)); MWBase::Environment::get().getWorld()->setupPlayer(); + input->setPlayer(&mEnvironment.getWorld()->getPlayer()); + + window->initUI(); + window->renderWorldMap(); //Load translation data mTranslationDataStorage.setEncoder(mEncoder); 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 Compiler::registerExtensions (mExtensions); - mEnvironment.setWindowManager (new MWGui::WindowManager( - mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), - mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding)); - if (mNewGame) - mEnvironment.getWindowManager()->setNewGame(true); - // Create sound system mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound)); @@ -422,16 +436,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setJournal (new MWDialogue::Journal); mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage)); - // Sets up the input system - - // Get the path for the keybinder xml file - std::string keybinderUser = (mCfgMgr.getUserPath() / "input.xml").string(); - bool keybinderUserExists = boost::filesystem::exists(keybinderUser); - - mEnvironment.setInputManager (new MWInput::InputManager (*mOgre, - MWBase::Environment::get().getWorld()->getPlayer(), - *MWBase::Environment::get().getWindowManager(), *this, keybinderUser, keybinderUserExists)); - mEnvironment.getWorld()->renderPlayer(); if (!mNewGame) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index b75f6753d..4d764597c 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -39,9 +39,11 @@ namespace MWBase Play_Normal = 0, /* tracked, non-looping, multi-instance, environment */ Play_Loop = 1<<0, /* Sound will continually loop until explicitly stopped */ Play_NoEnv = 1<<1, /* Do not apply environment effects (eg, underwater filters) */ - Play_NoTrack = 1<<2 /* (3D only) Play the sound at the given object's position + Play_NoTrack = 1<<2, /* (3D only) Play the sound at the given object's position * but do not keep it updated (the sound will not move with * the object and will not stop when the object is deleted. */ + + Play_LoopNoEnv = Play_Loop | Play_NoEnv }; enum PlayType { Play_TypeSfx = 1<<3, /* Normal SFX sound */ diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 77941a43a..1cd867223 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -9,6 +9,8 @@ #include +#include + #include "../mwmechanics/stat.hpp" #include "../mwgui/mode.hpp" @@ -253,9 +255,6 @@ namespace MWBase virtual void executeInConsole (const std::string& path) = 0; - virtual void setLoadingProgress (const std::string& stage, int depth, int current, int total) = 0; - virtual void loadingDone() = 0; - virtual void enableRest() = 0; virtual bool getRestEnabled() = 0; virtual bool getJournalAllowed() = 0; @@ -282,6 +281,8 @@ namespace MWBase virtual const Translation::Storage& getTranslationDataStorage() const = 0; virtual void setKeyFocusWidget (MyGUI::Widget* widget) = 0; + + virtual Loading::Listener* getLoadingScreen() = 0; }; } diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 3a60d9c39..583cb08d3 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -6,19 +6,26 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld//cellstore.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/action.hpp" +#include "../mwworld/failedaction.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwrender/actors.hpp" #include "../mwrender/renderinginterface.hpp" #include "../mwgui/tooltips.hpp" +#include "../mwmechanics/npcstats.hpp" + + namespace MWClass { - void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { const std::string model = getModel(ptr); if (!model.empty()) { @@ -94,7 +101,23 @@ namespace MWClass return info; } - + + boost::shared_ptr Activator::activate(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor) const + { + if(get(actor).isNpc() && get(actor).getNpcStats(actor).isWerewolf()) + { + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Sound *sound = store.get().searchRandom("WolfActivator"); + + boost::shared_ptr action(new MWWorld::FailedAction("#{sWerewolfRefusal}")); + if(sound) action->setSound(sound->mId); + + return action; + } + return boost::shared_ptr(new MWWorld::NullAction); + } + + MWWorld::Ptr Activator::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const { diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 4165fbc08..1e772ef4f 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -31,6 +31,9 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; + ///< Generate action for activation + static void registerSelf(); virtual std::string getModel(const MWWorld::Ptr &ptr) const; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 85c2cf5fb..bc869e5fe 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -88,8 +88,13 @@ namespace MWGui mDragAndDropWidget->setVisible(false); - targetModel->copyItem(mItem, mDraggedCount); - mSourceModel->removeItem(mItem, mDraggedCount); + // If item is dropped where it was taken from, we don't need to do anything - + // otherwise, do the transfer + if (targetModel != mSourceModel) + { + targetModel->copyItem(mItem, mDraggedCount); + mSourceModel->removeItem(mItem, mDraggedCount); + } mSourceModel->update(); diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index e23b4f77f..eff8fbcc1 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -74,13 +74,12 @@ ItemModel::ModelIndex ContainerItemModel::getIndex (ItemStack item) void ContainerItemModel::copyItem (const ItemStack& item, size_t count) { const MWWorld::Ptr& source = mItemSources[mItemSources.size()-1]; + if (item.mBase.getContainerStore() == &source.getClass().getContainerStore(source)) + throw std::runtime_error("Item to copy needs to be from a different container!"); int origCount = item.mBase.getRefData().getCount(); item.mBase.getRefData().setCount(count); - MWWorld::ContainerStoreIterator it = MWWorld::Class::get(source).getContainerStore(source).add(item.mBase, source); - if (*it != item.mBase) - item.mBase.getRefData().setCount(origCount); - else - item.mBase.getRefData().setCount(origCount + count); // item copied onto itself + source.getClass().getContainerStore(source).add(item.mBase, source); + item.mBase.getRefData().setCount(origCount); } void ContainerItemModel::removeItem (const ItemStack& item, size_t count) diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index ec3bb3b30..62a5a75f0 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -40,13 +40,12 @@ ItemModel::ModelIndex InventoryItemModel::getIndex (ItemStack item) void InventoryItemModel::copyItem (const ItemStack& item, size_t count) { + if (item.mBase.getContainerStore() == &mActor.getClass().getContainerStore(mActor)) + throw std::runtime_error("Item to copy needs to be from a different container!"); int origCount = item.mBase.getRefData().getCount(); item.mBase.getRefData().setCount(count); - MWWorld::ContainerStoreIterator it = MWWorld::Class::get(mActor).getContainerStore(mActor).add(item.mBase, mActor); - if (*it != item.mBase) - item.mBase.getRefData().setCount(origCount); - else - item.mBase.getRefData().setCount(origCount + count); // item copied onto itself + mActor.getClass().getContainerStore(mActor).add(item.mBase, mActor); + item.mBase.getRefData().setCount(origCount); } diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 547d2fe29..9b63dfa76 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -19,20 +19,16 @@ namespace MWGui : mSceneMgr(sceneMgr) , mWindow(rw) , WindowBase("openmw_loading_screen.layout") - , mLoadingOn(false) , mLastRenderTime(0.f) , mLastWallpaperChangeTime(0.f) , mFirstLoad(true) - , mTotalRefsLoading(0) - , mCurrentCellLoading(0) - , mTotalCellsLoading(0) - , mCurrentRefLoading(0) - , mCurrentRefList(0) + , mProgress(0) { getWidget(mLoadingText, "LoadingText"); getWidget(mProgressBar, "ProgressBar"); getWidget(mBackgroundImage, "BackgroundImage"); + mProgressBar->setScrollViewPage(1); mBackgroundMaterial = Ogre::MaterialManager::getSingleton().create("BackgroundMaterial", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); mBackgroundMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); @@ -54,6 +50,11 @@ namespace MWGui mRectangle->setVisible(false); } + void LoadingScreen::setLabel(const std::string &label) + { + mLoadingText->setCaptionWithReplacing(label); + } + LoadingScreen::~LoadingScreen() { delete mRectangle; @@ -64,149 +65,25 @@ namespace MWGui setCoord(0,0,w,h); } - void LoadingScreen::setLoadingProgress (const std::string& stage, int depth, int current, int total) - { - if (!mLoadingOn) - loadingOn(); - - const int numRefLists = 20; - - if (depth == 0) - { - mCurrentCellLoading = current; - mTotalCellsLoading = total; - - mCurrentRefLoading = 0; - mCurrentRefList = 0; - } - else if (depth == 1) - { - mCurrentRefLoading = current; - mTotalRefsLoading = total; - } - - assert (mTotalCellsLoading != 0); - - float refProgress; - if (mTotalRefsLoading <= 1) - refProgress = 1; - else - refProgress = float(mCurrentRefLoading) / float(mTotalRefsLoading-1); - refProgress += mCurrentRefList; - refProgress /= numRefLists; - - assert(refProgress <= 1 && refProgress >= 0); - - if (depth == 1 && mCurrentRefLoading == mTotalRefsLoading-1) - ++mCurrentRefList; - - float progress = (float(mCurrentCellLoading)+refProgress) / float(mTotalCellsLoading); - assert(progress <= 1 && progress >= 0); - - mLoadingText->setCaption(stage); - mProgressBar->setProgressPosition (static_cast(progress * 1000)); - - static float loadingScreenFps = 30.f; - - if (mTimer.getMilliseconds () > mLastRenderTime + (1.f/loadingScreenFps) * 1000.f) - { - float dt = mTimer.getMilliseconds () - mLastRenderTime; - mLastRenderTime = mTimer.getMilliseconds (); - - if (mFirstLoad && mTimer.getMilliseconds () > mLastWallpaperChangeTime + 3000*1) - { - mLastWallpaperChangeTime = mTimer.getMilliseconds (); - changeWallpaper(); - } - - // Turn off rendering except the GUI - mSceneMgr->clearSpecialCaseRenderQueues(); - // SCRQM_INCLUDE with RENDER_QUEUE_OVERLAY does not work. - for (int i = 0; i < Ogre::RENDER_QUEUE_MAX; ++i) - { - if (i > 0 && i < 96) - mSceneMgr->addSpecialCaseRenderQueue(i); - } - mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); - - // always update input before rendering something, otherwise mygui goes crazy when something was entered in the frame before - // (e.g. when using "coc" console command, it would enter an infinite loop and crash due to overflow) - MWBase::Environment::get().getInputManager()->update(0, true); - - Ogre::CompositorChain* chain = Ogre::CompositorManager::getSingleton().getCompositorChain(mWindow->getViewport(0)); - - bool hasCompositor = chain->getCompositor ("gbufferFinalizer"); - - - if (!hasCompositor) - { - mWindow->getViewport(0)->setClearEveryFrame(false); - } - else - { - if (!mFirstLoad) - { - mBackgroundMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(chain->getCompositor ("gbufferFinalizer")->getTextureInstance ("no_mrt_output", 0)->getName()); - mRectangle->setVisible(true); - } - - for (unsigned int i = 0; igetNumCompositors(); ++i) - { - Ogre::CompositorManager::getSingleton().setCompositorEnabled(mWindow->getViewport(0), chain->getCompositor(i)->getCompositor()->getName(), false); - } - } - - MWBase::Environment::get().getWorld ()->getFader ()->update (dt); - - mWindow->update(); - - if (!hasCompositor) - mWindow->getViewport(0)->setClearEveryFrame(true); - else - { - for (unsigned int i = 0; igetNumCompositors(); ++i) - { - Ogre::CompositorManager::getSingleton().setCompositorEnabled(mWindow->getViewport(0), chain->getCompositor(i)->getCompositor()->getName(), true); - } - } - - mRectangle->setVisible(false); - - // resume 3d rendering - mSceneMgr->clearSpecialCaseRenderQueues(); - mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); - } - } - - void LoadingScreen::loadingDone() - { - loadingOff(); - } - void LoadingScreen::loadingOn() { setVisible(true); - mLoadingOn = true; if (mFirstLoad) { changeWallpaper(); - - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_LoadingWallpaper); } else { mBackgroundImage->setImageTexture(""); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Loading); } - } + MWBase::Environment::get().getWindowManager()->pushGuiMode(mFirstLoad ? GM_LoadingWallpaper : GM_Loading); + } void LoadingScreen::loadingOff() { setVisible(false); - mLoadingOn = false; - mFirstLoad = false; MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Loading); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_LoadingWallpaper); @@ -235,4 +112,124 @@ namespace MWGui else std::cerr << "No loading screens found!" << std::endl; } + + void LoadingScreen::setProgressRange (size_t range) + { + mProgressBar->setScrollRange(range+1); + mProgressBar->setScrollPosition(0); + mProgressBar->setTrackSize(0); + mProgress = 0; + } + + void LoadingScreen::setProgress (size_t value) + { + assert(value < mProgressBar->getScrollRange()); + if (value - mProgress < mProgressBar->getScrollRange()/100.f) + return; + mProgress = value; + mProgressBar->setScrollPosition(0); + mProgressBar->setTrackSize(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize()); + draw(); + } + + void LoadingScreen::increaseProgress (size_t increase) + { + mProgressBar->setScrollPosition(0); + size_t value = mProgress + increase; + mProgress = value; + assert(mProgress < mProgressBar->getScrollRange()); + mProgressBar->setTrackSize(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize()); + draw(); + } + + void LoadingScreen::indicateProgress() + { + float time = (mTimer.getMilliseconds() % 2001) / 1000.f; + if (time > 1) + time = (time-2)*-1; + + mProgressBar->setTrackSize(50); + mProgressBar->setScrollPosition(time * (mProgressBar->getScrollRange()-1)); + draw(); + } + + void LoadingScreen::removeWallpaper() + { + mFirstLoad = false; + } + + void LoadingScreen::draw() + { + const float loadingScreenFps = 20.f; + + if (mTimer.getMilliseconds () > mLastRenderTime + (1.f/loadingScreenFps) * 1000.f) + { + mLastRenderTime = mTimer.getMilliseconds (); + + if (mFirstLoad && mTimer.getMilliseconds () > mLastWallpaperChangeTime + 5000*1) + { + mLastWallpaperChangeTime = mTimer.getMilliseconds (); + changeWallpaper(); + } + + // Turn off rendering except the GUI + mSceneMgr->clearSpecialCaseRenderQueues(); + // SCRQM_INCLUDE with RENDER_QUEUE_OVERLAY does not work. + for (int i = 0; i < Ogre::RENDER_QUEUE_MAX; ++i) + { + if (i > 0 && i < 96) + mSceneMgr->addSpecialCaseRenderQueue(i); + } + mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); + + MWBase::Environment::get().getInputManager()->update(0, true); + + Ogre::CompositorChain* chain = Ogre::CompositorManager::getSingleton().getCompositorChain(mWindow->getViewport(0)); + + bool hasCompositor = chain->getCompositor ("gbufferFinalizer"); + + + if (!hasCompositor) + { + mWindow->getViewport(0)->setClearEveryFrame(false); + } + else + { + if (!mFirstLoad) + { + mBackgroundMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(chain->getCompositor ("gbufferFinalizer")->getTextureInstance ("no_mrt_output", 0)->getName()); + mRectangle->setVisible(true); + } + + for (unsigned int i = 0; igetNumCompositors(); ++i) + { + Ogre::CompositorManager::getSingleton().setCompositorEnabled(mWindow->getViewport(0), chain->getCompositor(i)->getCompositor()->getName(), false); + } + } + + // First, swap buffers from last draw, then, queue an update of the + // window contents, but don't swap buffers (which would have + // caused a sync / flush and would be expensive). + // We're doing this so we can do some actual loading while the GPU is busy with the render. + // This means the render is lagging a frame behind, but this is hardly noticable. + mWindow->swapBuffers(false); // never Vsync, makes no sense here + mWindow->update(false); + + if (!hasCompositor) + mWindow->getViewport(0)->setClearEveryFrame(true); + else + { + for (unsigned int i = 0; igetNumCompositors(); ++i) + { + Ogre::CompositorManager::getSingleton().setCompositorEnabled(mWindow->getViewport(0), chain->getCompositor(i)->getCompositor()->getName(), true); + } + } + + mRectangle->setVisible(false); + + // resume 3d rendering + mSceneMgr->clearSpecialCaseRenderQueues(); + mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); + } + } } diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 87cedaa98..dde8ff63a 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -5,11 +5,27 @@ #include "windowbase.hpp" +#include + namespace MWGui { - class LoadingScreen : public WindowBase + class LoadingScreen : public WindowBase, public Loading::Listener { public: + virtual void setLabel (const std::string& label); + + /// Indicate that some progress has been made, without specifying how much + virtual void indicateProgress (); + + virtual void loadingOn(); + virtual void loadingOff(); + + virtual void setProgressRange (size_t range); + virtual void setProgress (size_t value); + virtual void increaseProgress (size_t increase); + + virtual void removeWallpaper(); + LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw); virtual ~LoadingScreen(); @@ -30,27 +46,20 @@ namespace MWGui unsigned long mLastRenderTime; Ogre::Timer mTimer; - MyGUI::TextBox* mLoadingText; - MyGUI::ProgressBar* mProgressBar; - MyGUI::ImageBox* mBackgroundImage; + size_t mProgress; - int mCurrentCellLoading; - int mTotalCellsLoading; - int mCurrentRefLoading; - int mTotalRefsLoading; - int mCurrentRefList; + MyGUI::TextBox* mLoadingText; + MyGUI::ScrollBar* mProgressBar; + MyGUI::ImageBox* mBackgroundImage; Ogre::Rectangle2D* mRectangle; Ogre::MaterialPtr mBackgroundMaterial; Ogre::StringVector mResources; - bool mLoadingOn; - - void loadingOn(); - void loadingOff(); - void changeWallpaper(); + + void draw(); }; } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 0ccfb7e88..5ed002d7b 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -260,12 +260,10 @@ namespace MWGui MapWindow::MapWindow(const std::string& cacheDir) : MWGui::WindowPinnableBase("openmw_map_window.layout") , mGlobal(false) + , mGlobalMap(0) { setCoord(500,0,320,300); - mGlobalMapRender = new MWRender::GlobalMap(cacheDir); - mGlobalMapRender->render(); - getWidget(mLocalMap, "LocalMap"); getWidget(mGlobalMap, "GlobalMap"); getWidget(mGlobalMapImage, "GlobalMapImage"); @@ -273,9 +271,6 @@ namespace MWGui getWidget(mPlayerArrowLocal, "CompassLocal"); getWidget(mPlayerArrowGlobal, "CompassGlobal"); - mGlobalMapImage->setImageTexture("GlobalMap.png"); - mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); - mGlobalMap->setVisible (false); getWidget(mButton, "WorldButton"); @@ -292,6 +287,14 @@ namespace MWGui LocalMapBase::init(mLocalMap, mPlayerArrowLocal, this); } + void MapWindow::renderGlobalMap(Loading::Listener* loadingListener) + { + mGlobalMapRender = new MWRender::GlobalMap(""); + mGlobalMapRender->render(loadingListener); + mGlobalMapImage->setImageTexture("GlobalMap.png"); + mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); + } + MapWindow::~MapWindow() { delete mGlobalMapRender; diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 3aefc398c..5518ab4a8 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -8,6 +8,11 @@ namespace MWRender class GlobalMap; } +namespace Loading +{ + class Listener; +} + namespace MWGui { class LocalMapBase @@ -71,6 +76,8 @@ namespace MWGui void setCellName(const std::string& cellName); + void renderGlobalMap(Loading::Listener* loadingListener); + void addVisitedLocation(const std::string& name, int x, int y); // adds the marker to the global map void cellExplored(int x, int y); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1cb1d80b0..bf8b664da 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -62,6 +62,7 @@ namespace MWGui const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding) : mGuiManager(NULL) + , mConsoleOnlyScripts(consoleOnlyScripts) , mRendering(ogre) , mHud(NULL) , mMap(NULL) @@ -156,7 +157,28 @@ namespace MWGui 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; + + mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow ()); + mLoadingScreen->onResChange (w,h); + + //set up the hardware cursor manager + mSoftwareCursor = new Cursor(); + mCursorManager = new SFO::SDLCursorManager(); + + MyGUI::PointerManager::getInstance().eventChangeMousePointer += MyGUI::newDelegate(this, &WindowManager::onCursorChange); + + MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged); + + setUseHardwareCursors(mUseHardwareCursors); + onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); + mCursorManager->cursorVisibilityChange(false); + } + + void WindowManager::initUI() + { + // Get size info from the Gui object int w = MyGUI::RenderManager::getInstance().getViewSize().width; int h = MyGUI::RenderManager::getInstance().getViewSize().height; @@ -169,9 +191,9 @@ namespace MWGui mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; mMenu = new MainMenu(w,h); - mMap = new MapWindow(cacheDir); + mMap = new MapWindow(""); mStatsWindow = new StatsWindow(); - mConsole = new Console(w,h, consoleOnlyScripts); + mConsole = new Console(w,h, mConsoleOnlyScripts); mJournal = JournalWindow::create(JournalViewModel::create ()); mMessageBoxManager = new MessageBoxManager(); mInventoryWindow = new InventoryWindow(mDragAndDrop); @@ -200,13 +222,8 @@ namespace MWGui 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",""); - mSoftwareCursor = new Cursor(); - mHud->setVisible(mHudEnabled); mCharGen = new CharacterCreation(); @@ -225,19 +242,15 @@ namespace MWGui unsetSelectedSpell(); unsetSelectedWeapon(); - //set up the hardware cursor manager - mCursorManager = new SFO::SDLCursorManager(); - - MyGUI::PointerManager::getInstance().eventChangeMousePointer += MyGUI::newDelegate(this, &WindowManager::onCursorChange); - - MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged); - - setUseHardwareCursors(mUseHardwareCursors); - onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); - mCursorManager->cursorVisibilityChange(false); - // Set up visibility updateVisible(); + + MWBase::Environment::get().getInputManager()->changeInputMode(false); + } + + void WindowManager::renderWorldMap() + { + mMap->renderGlobalMap(mLoadingScreen); } void WindowManager::setNewGame(bool newgame) @@ -329,6 +342,8 @@ namespace MWGui void WindowManager::updateVisible() { + if (!mMap) + return; // UI not created yet // Start out by hiding everything except the HUD mMap->setVisible(false); mMenu->setVisible(false); @@ -914,6 +929,10 @@ namespace MWGui void WindowManager::windowResized(int x, int y) { + mGuiManager->windowResized(); + mLoadingScreen->onResChange (x,y); + if (!mHud) + return; // UI not initialized yet mHud->onResChange(x, y); mConsole->onResChange(x, y); mMenu->onResChange(x, y); @@ -923,10 +942,8 @@ namespace MWGui mBookWindow->center(); mQuickKeysMenu->center(); mSpellBuyingWindow->center(); - mLoadingScreen->onResChange (x,y); mDragAndDrop->mDragAndDropWidget->setSize(MyGUI::IntSize(x, y)); mInputBlocker->setSize(MyGUI::IntSize(x,y)); - mGuiManager->windowResized(); } void WindowManager::pushGuiMode(GuiMode mode) @@ -1148,7 +1165,7 @@ namespace MWGui bool WindowManager::isGuiMode() const { - return !mGuiModes.empty() || mMessageBoxManager->isInteractiveMessageBox(); + return !mGuiModes.empty() || (mMessageBoxManager && mMessageBoxManager->isInteractiveMessageBox()); } bool WindowManager::isConsoleMode() const @@ -1211,7 +1228,8 @@ namespace MWGui void WindowManager::showCrosshair (bool show) { - mHud->setCrosshairVisible (show && mCrosshairEnabled); + if (mHud) + mHud->setCrosshairVisible (show && mCrosshairEnabled); } void WindowManager::activateQuickKey (int index) @@ -1230,15 +1248,6 @@ namespace MWGui 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::getRestEnabled() { //Enable rest dialogue if character creation finished @@ -1345,4 +1354,9 @@ namespace MWGui mHud->setEnemy(enemy); } + Loading::Listener* WindowManager::getLoadingScreen() + { + return mLoadingScreen; + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index e49b33647..badb333a7 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -91,6 +91,11 @@ namespace MWGui Translation::Storage& translationDataStorage, ToUTF8::FromType encoding); virtual ~WindowManager(); + void initUI(); + void renderWorldMap(); + + virtual Loading::Listener* getLoadingScreen(); + /** * Should be called each frame to update windows/gui elements. * This could mean updating sizes of gui elements or opening @@ -241,9 +246,6 @@ namespace MWGui virtual void executeInConsole (const std::string& path); - virtual void setLoadingProgress (const std::string& stage, int depth, int current, int total); - virtual void loadingDone(); - virtual void enableRest() { mRestAllowed = true; } virtual bool getRestEnabled(); @@ -275,6 +277,8 @@ namespace MWGui void onSoulgemDialogButtonPressed (int button); private: + bool mConsoleOnlyScripts; + OEngine::GUI::MyGUIManager *mGuiManager; OEngine::Render::OgreRenderer *mRendering; HUD *mHud; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 573fe389c..1039a0dce 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -86,13 +86,10 @@ namespace namespace MWInput { InputManager::InputManager(OEngine::Render::OgreRenderer &ogre, - MWWorld::Player& player, - MWBase::WindowManager &windows, OMW::Engine& engine, const std::string& userFile, bool userFileExists) : mOgre(ogre) - , mPlayer(player) - , mWindows(windows) + , mPlayer(NULL) , mEngine(engine) , mMouseLookEnabled(true) , mMouseX(ogre.getWindow()->getWidth ()/2.f) @@ -124,8 +121,6 @@ namespace MWInput adjustMouseRegion (window->getWidth(), window->getHeight()); - MyGUI::InputManager::getInstance().injectMouseMove(mMouseX, mMouseY, 0); - loadKeyDefaults(); for (int i = 0; i < A_Last; ++i) @@ -140,8 +135,6 @@ namespace MWInput mControlSwitch["playermagic"] = true; mControlSwitch["playerviewswitch"] = true; mControlSwitch["vanitymode"] = true; - - changeInputMode(false); } InputManager::~InputManager() @@ -164,7 +157,7 @@ namespace MWInput if (action == A_Use) { - MWWorld::Class::get(mPlayer.getPlayer()).getCreatureStats(mPlayer.getPlayer()).setAttackingOrSpell(currentValue); + MWWorld::Class::get(mPlayer->getPlayer()).getCreatureStats(mPlayer->getPlayer()).setAttackingOrSpell(currentValue); if (currentValue == 1) { int type = MWMechanics::CreatureStats::AT_Chop; @@ -177,7 +170,7 @@ namespace MWInput if (forward && !side) type = MWMechanics::CreatureStats::AT_Thrust; - MWWorld::Class::get(mPlayer.getPlayer()).getCreatureStats(mPlayer.getPlayer()).setAttackType(type); + MWWorld::Class::get(mPlayer->getPlayer()).getCreatureStats(mPlayer->getPlayer()).setAttackType(type); } } @@ -204,9 +197,9 @@ namespace MWInput case A_Activate: resetIdleTime(); - if (mWindows.isGuiMode()) + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { - if (mWindows.getMode() == MWGui::GM_Container) + if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Container) toggleContainer (); else MWBase::Environment::get().getWindowManager()->activateKeyPressed(); @@ -266,7 +259,7 @@ namespace MWInput showQuickKeysMenu(); break; case A_ToggleHUD: - mWindows.toggleHud(); + MWBase::Environment::get().getWindowManager()->toggleHud(); break; } } @@ -274,8 +267,7 @@ namespace MWInput void InputManager::update(float dt, bool loading) { - // Tell OIS to handle all input events - mInputManager->capture(); + mInputManager->capture(loading); // inject some fake mouse movement to force updating MyGUI's widget states // this shouldn't do any harm since we're moving back to the original position afterwards MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX+1), int(mMouseY+1), mMouseWheel); @@ -285,18 +277,10 @@ namespace MWInput if (!loading) mInputBinder->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 - // ensure that window/gui changes appear quickly while - // avoiding that window/gui changes does not happen in - // event callbacks (which may crash) - mWindows.update(); - - bool main_menu = mWindows.containsMode(MWGui::GM_MainMenu); + bool main_menu = MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu); bool was_relative = mInputManager->getMouseRelative(); - bool is_relative = !mWindows.isGuiMode(); + bool is_relative = !MWBase::Environment::get().getWindowManager()->isGuiMode(); // don't keep the pointer away from the window edge in gui mode // stop using raw mouse motions and switch to system cursor movements @@ -312,8 +296,11 @@ namespace MWInput mInputManager->warpMouse(mMouseX, mMouseY); } + if (loading) + return; + // Disable movement in Gui mode - if (mWindows.isGuiMode()) return; + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; // Configure player movement according to keyboard input. Actual movement will @@ -324,45 +311,45 @@ namespace MWInput if (actionIsActive(A_MoveLeft)) { triedToMove = true; - mPlayer.setLeftRight (-1); + mPlayer->setLeftRight (-1); } else if (actionIsActive(A_MoveRight)) { triedToMove = true; - mPlayer.setLeftRight (1); + mPlayer->setLeftRight (1); } if (actionIsActive(A_MoveForward)) { triedToMove = true; - mPlayer.setAutoMove (false); - mPlayer.setForwardBackward (1); + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (1); } else if (actionIsActive(A_MoveBackward)) { triedToMove = true; - mPlayer.setAutoMove (false); - mPlayer.setForwardBackward (-1); + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (-1); } - else if(mPlayer.getAutoMove()) + else if(mPlayer->getAutoMove()) { triedToMove = true; - mPlayer.setForwardBackward (1); + mPlayer->setForwardBackward (1); } - mPlayer.setSneak(actionIsActive(A_Sneak)); + mPlayer->setSneak(actionIsActive(A_Sneak)); if (actionIsActive(A_Jump) && mControlSwitch["playerjumping"]) { - mPlayer.setUpDown (1); + mPlayer->setUpDown (1); triedToMove = true; } if (mAlwaysRunActive) - mPlayer.setRunState(!actionIsActive(A_Run)); + mPlayer->setRunState(!actionIsActive(A_Run)); else - mPlayer.setRunState(actionIsActive(A_Run)); + mPlayer->setRunState(actionIsActive(A_Run)); // if player tried to start moving, but can't (due to being overencumbered), display a notification. if (triedToMove) @@ -371,7 +358,7 @@ namespace MWInput mOverencumberedMessageDelay -= dt; if (MWWorld::Class::get(player).getEncumbrance(player) >= MWWorld::Class::get(player).getCapacity(player)) { - mPlayer.setAutoMove (false); + mPlayer->setAutoMove (false); if (mOverencumberedMessageDelay <= 0) { MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage59}"); @@ -425,8 +412,8 @@ namespace MWInput mGuiCursorEnabled = guiMode; mMouseLookEnabled = !guiMode; if (guiMode) - mWindows.showCrosshair(false); - mWindows.setCursorVisible(guiMode); + MWBase::Environment::get().getWindowManager()->showCrosshair(false); + MWBase::Environment::get().getWindowManager()->setCursorVisible(guiMode); // if not in gui mode, the camera decides whether to show crosshair or not. } @@ -459,13 +446,13 @@ namespace MWInput } /// \note 7 switches at all, if-else is relevant if (sw == "playercontrols" && !value) { - mPlayer.setLeftRight(0); - mPlayer.setForwardBackward(0); - mPlayer.setAutoMove(false); - mPlayer.setUpDown(0); + mPlayer->setLeftRight(0); + mPlayer->setForwardBackward(0); + mPlayer->setAutoMove(false); + mPlayer->setUpDown(0); } else if (sw == "playerjumping" && !value) { /// \fixme maybe crouching at this time - mPlayer.setUpDown(0); + mPlayer->setUpDown(0); } else if (sw == "vanitymode") { MWBase::Environment::get().getWorld()->allowVanityMode(value); } else if (sw == "playerlooking") { @@ -594,8 +581,8 @@ namespace MWInput // Only actually turn player when we're not in vanity mode if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot)) { - mPlayer.yaw(x/scale); - mPlayer.pitch(-y/scale); + mPlayer->yaw(x/scale); + mPlayer->pitch(-y/scale); } if (arg.zrel) @@ -627,51 +614,51 @@ namespace MWInput if (MyGUI::InputManager::getInstance ().isModalAny()) return; - if (mWindows.isGuiMode () && mWindows.getMode () == MWGui::GM_Video) + if (MWBase::Environment::get().getWindowManager()->isGuiMode () && MWBase::Environment::get().getWindowManager()->getMode () == MWGui::GM_Video) MWBase::Environment::get().getWorld ()->stopVideo (); - else if (mWindows.containsMode(MWGui::GM_MainMenu)) - mWindows.popGuiMode(); + else if (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu)) + MWBase::Environment::get().getWindowManager()->popGuiMode(); else - mWindows.pushGuiMode (MWGui::GM_MainMenu); + MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); } void InputManager::toggleSpell() { - if (mWindows.isGuiMode()) return; + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; // Not allowed before the magic window is accessible - if (!mWindows.isAllowed(MWGui::GW_Magic)) + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Magic)) return; - MWMechanics::DrawState_ state = mPlayer.getDrawState(); + MWMechanics::DrawState_ state = mPlayer->getDrawState(); if (state == MWMechanics::DrawState_Weapon || state == MWMechanics::DrawState_Nothing) - mPlayer.setDrawState(MWMechanics::DrawState_Spell); + mPlayer->setDrawState(MWMechanics::DrawState_Spell); else - mPlayer.setDrawState(MWMechanics::DrawState_Nothing); + mPlayer->setDrawState(MWMechanics::DrawState_Nothing); } void InputManager::toggleWeapon() { - if (mWindows.isGuiMode()) return; + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; // Not allowed before the inventory window is accessible - if (!mWindows.isAllowed(MWGui::GW_Inventory)) + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) return; - MWMechanics::DrawState_ state = mPlayer.getDrawState(); + MWMechanics::DrawState_ state = mPlayer->getDrawState(); if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing) - mPlayer.setDrawState(MWMechanics::DrawState_Weapon); + mPlayer->setDrawState(MWMechanics::DrawState_Weapon); else - mPlayer.setDrawState(MWMechanics::DrawState_Nothing); + mPlayer->setDrawState(MWMechanics::DrawState_Nothing); } void InputManager::rest() { - if (!mWindows.getRestEnabled () || mWindows.isGuiMode ()) + if (!MWBase::Environment::get().getWindowManager()->getRestEnabled () || MWBase::Environment::get().getWindowManager()->isGuiMode ()) return; /// \todo check if resting is currently allowed (enemies nearby?) - mWindows.pushGuiMode (MWGui::GM_Rest); + MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_Rest); } void InputManager::screenshot() @@ -679,7 +666,7 @@ namespace MWInput mEngine.screenshot(); std::vector empty; - mWindows.messageBox ("Screenshot saved", empty); + MWBase::Environment::get().getWindowManager()->messageBox ("Screenshot saved", empty); } void InputManager::toggleInventory() @@ -688,13 +675,13 @@ namespace MWInput return; // Toggle between game mode and inventory mode - if(!mWindows.isGuiMode()) - mWindows.pushGuiMode(MWGui::GM_Inventory); + if(!MWBase::Environment::get().getWindowManager()->isGuiMode()) + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Inventory); else { - MWGui::GuiMode mode = mWindows.getMode(); + MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); if(mode == MWGui::GM_Inventory || mode == MWGui::GM_Container) - mWindows.popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } // .. but don't touch any other mode, except container. @@ -705,12 +692,12 @@ namespace MWInput if (MyGUI::InputManager::getInstance ().isModalAny()) return; - if(mWindows.isGuiMode()) + if(MWBase::Environment::get().getWindowManager()->isGuiMode()) { - if (mWindows.getMode() == MWGui::GM_Container) - mWindows.popGuiMode(); + if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Container) + MWBase::Environment::get().getWindowManager()->popGuiMode(); else - mWindows.pushGuiMode(MWGui::GM_Container); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container); } } @@ -722,15 +709,15 @@ namespace MWInput // Switch to console mode no matter what mode we are currently // in, except of course if we are already in console mode - if (mWindows.isGuiMode()) + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { - if (mWindows.getMode() == MWGui::GM_Console) - mWindows.popGuiMode(); + if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Console) + MWBase::Environment::get().getWindowManager()->popGuiMode(); else - mWindows.pushGuiMode(MWGui::GM_Console); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Console); } else - mWindows.pushGuiMode(MWGui::GM_Console); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Console); } void InputManager::toggleJournal() @@ -739,31 +726,31 @@ namespace MWInput return; // Toggle between game mode and journal mode - if(!mWindows.isGuiMode() && MWBase::Environment::get().getWindowManager ()->getJournalAllowed()) + if(!MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager ()->getJournalAllowed()) { MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); - mWindows.pushGuiMode(MWGui::GM_Journal); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Journal); } - else if(mWindows.getMode() == MWGui::GM_Journal) + else if(MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Journal) { MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); - mWindows.popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } // .. but don't touch any other mode. } void InputManager::quickKey (int index) { - if (!mWindows.isGuiMode()) - mWindows.activateQuickKey (index); + if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) + MWBase::Environment::get().getWindowManager()->activateQuickKey (index); } void InputManager::showQuickKeysMenu() { - if (!mWindows.isGuiMode ()) - mWindows.pushGuiMode (MWGui::GM_QuickKeysMenu); - else if (mWindows.getMode () == MWGui::GM_QuickKeysMenu) - mWindows.removeGuiMode (MWGui::GM_QuickKeysMenu); + if (!MWBase::Environment::get().getWindowManager()->isGuiMode ()) + MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_QuickKeysMenu); + else if (MWBase::Environment::get().getWindowManager()->getMode () == MWGui::GM_QuickKeysMenu) + MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_QuickKeysMenu); } void InputManager::activate() @@ -774,22 +761,22 @@ namespace MWInput void InputManager::toggleAutoMove() { - if (mWindows.isGuiMode()) return; + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; if (mControlSwitch["playercontrols"]) - mPlayer.setAutoMove (!mPlayer.getAutoMove()); + mPlayer->setAutoMove (!mPlayer->getAutoMove()); } void InputManager::toggleWalking() { - if (mWindows.isGuiMode()) return; + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; mAlwaysRunActive = !mAlwaysRunActive; } // Exit program now button (which is disabled in GUI mode) void InputManager::exitNow() { - if(!mWindows.isGuiMode()) + if(!MWBase::Environment::get().getWindowManager()->isGuiMode()) Ogre::Root::getSingleton().queueEndRendering (); } diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index ef7ef75a8..5f9a752d7 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -60,8 +60,6 @@ namespace MWInput { public: InputManager(OEngine::Render::OgreRenderer &_ogre, - MWWorld::Player&_player, - MWBase::WindowManager &_windows, OMW::Engine& engine, const std::string& userFile, bool userFileExists); @@ -69,6 +67,8 @@ namespace MWInput virtual void update(float dt, bool loading); + void setPlayer (MWWorld::Player* player) { mPlayer = player; } + virtual void changeInputMode(bool guiMode); virtual void processChangedSettings(const Settings::CategorySettingVector& changed); @@ -125,8 +125,7 @@ namespace MWInput private: OEngine::Render::OgreRenderer &mOgre; - MWWorld::Player& mPlayer; - MWBase::WindowManager &mWindows; + MWWorld::Player* mPlayer; OMW::Engine& mEngine; ICS::InputControlSystem* mInputBinder; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a6db0a909..f5caff359 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -11,10 +11,12 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/player.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/soundmanager.hpp" #include "npcstats.hpp" #include "creaturestats.hpp" @@ -68,22 +70,24 @@ namespace MWMechanics { CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); - int strength = creatureStats.getAttribute(0).getBase(); - int intelligence = creatureStats.getAttribute(1).getBase(); - int willpower = creatureStats.getAttribute(2).getBase(); - int agility = creatureStats.getAttribute(3).getBase(); - int endurance = creatureStats.getAttribute(5).getBase(); + int strength = creatureStats.getAttribute(ESM::Attribute::Strength).getBase(); + int intelligence = creatureStats.getAttribute(ESM::Attribute::Intelligence).getBase(); + int willpower = creatureStats.getAttribute(ESM::Attribute::Willpower).getBase(); + int agility = creatureStats.getAttribute(ESM::Attribute::Agility).getBase(); + int endurance = creatureStats.getAttribute(ESM::Attribute::Endurance).getBase(); double magickaFactor = creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::FortifyMaximumMagicka)).mMagnitude * 0.1 + 0.5; DynamicStat magicka = creatureStats.getMagicka(); - magicka.setBase (static_cast (intelligence + magickaFactor * intelligence)); - creatureStats.setMagicka (magicka); + float diff = (static_cast(intelligence + magickaFactor*intelligence)) - magicka.getBase(); + magicka.modify(diff); + creatureStats.setMagicka(magicka); DynamicStat fatigue = creatureStats.getFatigue(); - fatigue.setBase (strength+willpower+agility+endurance); - creatureStats.setFatigue (fatigue); + diff = (strength+willpower+agility+endurance) - fatigue.getBase(); + fatigue.modify(diff); + creatureStats.setFatigue(fatigue); } void Actors::calculateRestoration (const MWWorld::Ptr& ptr, float duration) @@ -133,62 +137,63 @@ namespace MWMechanics void Actors::calculateCreatureStatModifiers (const MWWorld::Ptr& ptr) { - CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); + CreatureStats &creatureStats = MWWorld::Class::get(ptr).getCreatureStats(ptr); + const MagicEffects &effects = creatureStats.getMagicEffects(); // attributes - for (int i=0; i<8; ++i) + for(int i = 0;i < ESM::Attribute::Length;++i) { - int modifier = - creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::FortifyAttribute, i)).mMagnitude; + Stat stat = creatureStats.getAttribute(i); + stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).mMagnitude - + effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).mMagnitude); - modifier -= creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::DrainAttribute, i)).mMagnitude; - - creatureStats.getAttribute(i).setModifier (modifier); + creatureStats.setAttribute(i, stat); } // dynamic stats - MagicEffects effects = creatureStats.getMagicEffects(); - - for (int i=0; i<3; ++i) + for(int i = 0;i < 3;++i) { - DynamicStat stat = creatureStats.getDynamic (i); + DynamicStat stat = creatureStats.getDynamic(i); + stat.setModifier(effects.get(EffectKey(80+i)).mMagnitude - + effects.get(EffectKey(18+i)).mMagnitude); - stat.setModifier ( - effects.get (EffectKey(80+i)).mMagnitude - effects.get (EffectKey(18+i)).mMagnitude); - - creatureStats.setDynamic (i, stat); + creatureStats.setDynamic(i, stat); } } void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration) { - NpcStats &stats = MWWorld::Class::get(ptr).getNpcStats(ptr); - if(MWBase::Environment::get().getWorld()->isSubmerged(ptr) && + MWBase::World *world = MWBase::Environment::get().getWorld(); + NpcStats &stats = ptr.getClass().getNpcStats(ptr); + if(world->isSubmerged(ptr) && stats.getMagicEffects().get(ESM::MagicEffect::WaterBreathing).mMagnitude == 0) { + float timeLeft = 0.0f; if(stats.getFatigue().getCurrent() == 0) stats.setTimeToStartDrowning(0); - - float timeLeft = stats.getTimeToStartDrowning()-duration; - if(timeLeft < 0.0f) - timeLeft = 0.0f; - - stats.setTimeToStartDrowning(timeLeft); + else + { + timeLeft = stats.getTimeToStartDrowning() - duration; + if(timeLeft < 0.0f) + timeLeft = 0.0f; + stats.setTimeToStartDrowning(timeLeft); + } if(timeLeft == 0.0f) - stats.setLastDrowningHitTime(stats.getLastDrowningHitTime()+duration); + { + // If drowning, apply 3 points of damage per second + ptr.getClass().setActorHealth(ptr, stats.getHealth().getCurrent() - 3.0f*duration); + + // Play a drowning sound as necessary for the player + if(ptr == world->getPlayer().getPlayer()) + { + MWBase::SoundManager *sndmgr = MWBase::Environment::get().getSoundManager(); + if(!sndmgr->getSoundPlaying(MWWorld::Ptr(), "drown")) + sndmgr->playSound("drown", 1.0f, 1.0f); + } + } } else - { stats.setTimeToStartDrowning(20); - stats.setLastDrowningHitTime(0); - } - //if npc is drowning and it's time to hit, then hit - while(stats.getTimeToStartDrowning() == 0.0f && stats.getLastDrowningHitTime() > 0.33f) - { - stats.setLastDrowningHitTime(stats.getLastDrowningHitTime()-0.33f); - //fixme: replace it with something different once screen hit effects are implemented (blood on screen) - MWWorld::Class::get(ptr).setActorHealth(ptr, stats.getHealth().getCurrent()-1.0f); - } } Actors::Actors() : mDuration (0) {} diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index c559e4445..8c13db790 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -8,7 +8,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/dialoguemanager.hpp" -#include "../mwbase/soundmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -189,6 +188,9 @@ namespace MWMechanics void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { + if(old == mWatched) + mWatched = ptr; + if(MWWorld::Class::get(ptr).isActor()) mActors.updateActor(old, ptr); else @@ -213,98 +215,76 @@ namespace MWMechanics void MechanicsManager::update(float duration, bool paused) { - if (!mWatched.isEmpty()) + if(!mWatched.isEmpty()) { - MWMechanics::CreatureStats& stats = - MWWorld::Class::get (mWatched).getCreatureStats (mWatched); - - MWMechanics::NpcStats& npcStats = - MWWorld::Class::get (mWatched).getNpcStats (mWatched); - - static const char *attributeNames[8] = + MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager(); + const MWMechanics::NpcStats &stats = mWatched.getClass().getNpcStats(mWatched); + for(int i = 0;i < ESM::Attribute::Length;++i) { - "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", - "AttribVal6", "AttribVal7", "AttribVal8" - }; - - static const char *dynamicNames[3] = - { - "HBar", "MBar", "FBar" - }; - - for (int i=0; i<8; ++i) - { - if (stats.getAttribute(i)!=mWatchedCreature.getAttribute(i)) + if(stats.getAttribute(i) != mWatchedStats.getAttribute(i)) { - mWatchedCreature.setAttribute(i, stats.getAttribute(i)); + std::stringstream attrname; + attrname << "AttribVal"<<(i+1); - MWBase::Environment::get().getWindowManager()->setValue (attributeNames[i], stats.getAttribute(i)); + mWatchedStats.setAttribute(i, stats.getAttribute(i)); + winMgr->setValue(attrname.str(), stats.getAttribute(i)); } } - if (stats.getHealth() != mWatchedCreature.getHealth()) { - mWatchedCreature.setHealth(stats.getHealth()); - MWBase::Environment::get().getWindowManager()->setValue(dynamicNames[0], stats.getHealth()); + if(stats.getHealth() != mWatchedStats.getHealth()) + { + static const std::string hbar("HBar"); + mWatchedStats.setHealth(stats.getHealth()); + winMgr->setValue(hbar, stats.getHealth()); } - if (stats.getMagicka() != mWatchedCreature.getMagicka()) { - mWatchedCreature.setMagicka(stats.getMagicka()); - MWBase::Environment::get().getWindowManager()->setValue(dynamicNames[1], stats.getMagicka()); + if(stats.getMagicka() != mWatchedStats.getMagicka()) + { + static const std::string mbar("MBar"); + mWatchedStats.setMagicka(stats.getMagicka()); + winMgr->setValue(mbar, stats.getMagicka()); } - if (stats.getFatigue() != mWatchedCreature.getFatigue()) { - mWatchedCreature.setFatigue(stats.getFatigue()); - MWBase::Environment::get().getWindowManager()->setValue(dynamicNames[2], stats.getFatigue()); + if(stats.getFatigue() != mWatchedStats.getFatigue()) + { + static const std::string fbar("FBar"); + mWatchedStats.setFatigue(stats.getFatigue()); + winMgr->setValue(fbar, stats.getFatigue()); } - if(npcStats.getTimeToStartDrowning() != mWatchedNpc.getTimeToStartDrowning()) + if(stats.getTimeToStartDrowning() != mWatchedStats.getTimeToStartDrowning()) { - mWatchedNpc.setTimeToStartDrowning(npcStats.getTimeToStartDrowning()); - if(npcStats.getTimeToStartDrowning()>=20.0) - { - MWBase::Environment::get().getWindowManager()->setDrowningBarVisibility(false); - } + mWatchedStats.setTimeToStartDrowning(stats.getTimeToStartDrowning()); + if(stats.getTimeToStartDrowning() >= 20.0f) + winMgr->setDrowningBarVisibility(false); else { - MWBase::Environment::get().getWindowManager()->setDrowningBarVisibility(true); - MWBase::Environment::get().getWindowManager()->setDrowningTimeLeft(npcStats.getTimeToStartDrowning()); + winMgr->setDrowningBarVisibility(true); + winMgr->setDrowningTimeLeft(stats.getTimeToStartDrowning()); } } bool update = false; //Loop over ESM::Skill::SkillEnum - for(int i = 0; i < 27; ++i) + for(int i = 0; i < ESM::Skill::Length; ++i) { - if(npcStats.getSkill (i) != mWatchedNpc.getSkill (i)) + if(stats.getSkill(i) != mWatchedStats.getSkill(i)) { update = true; - mWatchedNpc.getSkill (i) = npcStats.getSkill (i); - MWBase::Environment::get().getWindowManager()->setValue((ESM::Skill::SkillEnum)i, npcStats.getSkill (i)); + mWatchedStats.getSkill(i) = stats.getSkill(i); + winMgr->setValue((ESM::Skill::SkillEnum)i, stats.getSkill(i)); } } - if (update) - MWBase::Environment::get().getWindowManager()->updateSkillArea(); + if(update) + winMgr->updateSkillArea(); - MWBase::Environment::get().getWindowManager()->setValue ("level", stats.getLevel()); - } - - //update drowning sound - MWBase::World *world = MWBase::Environment::get().getWorld(); - MWBase::SoundManager * sndmgr = MWBase::Environment::get().getSoundManager(); - MWWorld::Ptr playerPtr = world->getPlayer().getPlayer(); - NpcStats& playerStats = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); - if(!sndmgr->getSoundPlaying(MWWorld::Ptr(), "drown") && playerStats.getTimeToStartDrowning()==0.0) - { - sndmgr->playSound("drown",1.0,1.0,MWBase::SoundManager::Play_TypeSfx,MWBase::SoundManager::Play_Loop); - } - if(playerStats.getTimeToStartDrowning()>0.0) - { - //no need to check if it's playing, stop sound does nothing in that case - sndmgr->stopSound("drown"); + winMgr->setValue("level", stats.getLevel()); } if (mUpdatePlayer) { + MWBase::World *world = MWBase::Environment::get().getWorld(); + // basic player profile; should not change anymore after the creation phase is finished. MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 95f760d11..ad07562c7 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -25,8 +25,7 @@ namespace MWMechanics class MechanicsManager : public MWBase::MechanicsManager { MWWorld::Ptr mWatched; - CreatureStats mWatchedCreature; - NpcStats mWatchedNpc; + NpcStats mWatchedStats; bool mUpdatePlayer; bool mClassSelected; bool mRaceSelected; diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 6a5e5a98f..0b3698289 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -422,7 +422,7 @@ void MWMechanics::NpcStats::modifyProfit(int diff) mProfit += diff; } -float MWMechanics::NpcStats::getTimeToStartDrowning() +float MWMechanics::NpcStats::getTimeToStartDrowning() const { return mTimeToStartDrowning; } @@ -431,13 +431,3 @@ void MWMechanics::NpcStats::setTimeToStartDrowning(float time) assert(time>=0 && time<=20); mTimeToStartDrowning=time; } - -float MWMechanics::NpcStats::getLastDrowningHitTime() -{ - return mLastDrowningHit; -} - -void MWMechanics::NpcStats::setLastDrowningHitTime(float time) -{ - mLastDrowningHit=time; -} diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index d3fe61829..6b7efa5b7 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -147,15 +147,10 @@ namespace MWMechanics int getWerewolfKills() const; - float getTimeToStartDrowning(); + float getTimeToStartDrowning() const; /// Sets time left for the creature to drown if it stays underwater. /// @param time value from [0,20] void setTimeToStartDrowning(float time); - - float getLastDrowningHitTime(); - /// Sets time since last hit caused by drowning. - /// @param time value from [0,0.33] - void setLastDrowningHitTime(float time); }; } diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 606671389..65d47c9c0 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -42,6 +42,18 @@ namespace MWMechanics mBase = mModified = value; } + void modify(const T& diff) + { + mBase += diff; + if(mBase >= static_cast(0)) + mModified += diff; + else + { + mModified += diff - mBase; + mBase = static_cast(0); + } + } + /// Set base and adjust modified accordingly. void setBase (const T& value) { diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f44f53a74..545060fe3 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -64,7 +64,7 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL Animation::Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node) : mPtr(ptr) , mCamera(NULL) - , mInsert(NULL) + , mInsert(node) , mSkelBase(NULL) , mAccumRoot(NULL) , mNonAccumRoot(NULL) @@ -74,20 +74,14 @@ Animation::Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node) { for(size_t i = 0;i < sNumGroups;i++) mAnimationValuePtr[i].bind(OGRE_NEW AnimationValue(this)); - mInsert = node->createChildSceneNode(); } Animation::~Animation() { - if(mInsert) - { - mAnimSources.clear(); + mAnimSources.clear(); - Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - destroyObjectList(sceneMgr, mObjectRoot); - - sceneMgr->destroySceneNode(mInsert); - } + Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + destroyObjectList(sceneMgr, mObjectRoot); } @@ -268,8 +262,13 @@ void Animation::addAnimSource(const std::string &model) if(!mAccumRoot && grp == 0) { - mAccumRoot = mInsert; mNonAccumRoot = dstval->getNode(); + mAccumRoot = mNonAccumRoot->getParent(); + if(!mAccumRoot) + { + std::cerr<< "Non-Accum root for "<getParentSceneNode()->getScale(); + Ogre::Vector3 extents = getWorldBounds().getSize(); float size = std::max(std::max(extents.x, extents.y), extents.z); bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) && diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 78b13ec07..120a83fae 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -28,7 +30,7 @@ namespace MWRender } - void GlobalMap::render () + void GlobalMap::render (Loading::Listener* loadingListener) { Ogre::TexturePtr tex; @@ -53,6 +55,11 @@ namespace MWRender mWidth = cellSize*(mMaxX-mMinX+1); mHeight = cellSize*(mMaxY-mMinY+1); + loadingListener->loadingOn(); + loadingListener->setLabel("Creating map"); + loadingListener->setProgressRange((mMaxX-mMinX+1) * (mMaxY-mMinY+1)); + loadingListener->setProgress(0); + mExploredBuffer.resize((mMaxX-mMinX+1) * (mMaxY-mMinY+1) * 4); //if (!boost::filesystem::exists(mCacheDir + "/GlobalMap.png")) @@ -147,6 +154,7 @@ namespace MWRender data[texelY * mWidth * 3 + texelX * 3+2] = b; } } + loadingListener->increaseProgress(1); } } @@ -177,6 +185,8 @@ namespace MWRender memcpy(mOverlayTexture->getBuffer()->lock(Ogre::HardwareBuffer::HBL_DISCARD), &buffer[0], mWidth*mHeight*4); mOverlayTexture->getBuffer()->unlock(); + + loadingListener->loadingOff(); } void GlobalMap::worldPosToImageSpace(float x, float z, float& imageX, float& imageY) diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index c01182c5b..dd3787b62 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -5,6 +5,11 @@ #include +namespace Loading +{ + class Listener; +} + namespace MWRender { @@ -13,7 +18,7 @@ namespace MWRender public: GlobalMap(const std::string& cacheDir); - void render(); + void render(Loading::Listener* loadingListener); int getWidth() { return mWidth; } int getHeight() { return mHeight; } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 337327dc4..fd81baf6e 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -130,7 +130,10 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh) // - the culling will be more inefficient // If it is set too low: // - there will be too many batches. - sg->setRegionDimensions(Ogre::Vector3(2500,2500,2500)); + if(ptr.getCell()->isExterior()) + sg->setRegionDimensions(Ogre::Vector3(2048,2048,2048)); + else + sg->setRegionDimensions(Ogre::Vector3(1024,1024,1024)); sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ade871a94..e03b2ccfc 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" @@ -82,7 +82,7 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b Settings::Manager::setString("shader mode", "General", openGL ? (glES ? "glsles" : "glsl") : "hlsl"); } - mRendering.createScene("PlayerCam", Settings::Manager::getFloat("field of view", "General"), 5); + mRendering.adjustCamera(Settings::Manager::getFloat("field of view", "General"), 5); mRendering.getWindow()->addListener(this); mRendering.setWindowListener(this); @@ -652,7 +652,8 @@ void RenderingManager::requestMap(MWWorld::Ptr::CellStore* cell) Ogre::Vector2 center(cell->mCell->getGridX() + 0.5, cell->mCell->getGridY() + 0.5); dims.merge(mTerrain->getWorldBoundingBox(center)); - mTerrain->update(dims.getCenter()); + if (dims.isFinite()) + mTerrain->update(dims.getCenter()); mLocalMap->requestMap(cell, dims.getMinimum().z, dims.getMaximum().z); } @@ -1017,12 +1018,15 @@ void RenderingManager::enableTerrain(bool enable) { if (!mTerrain) { - mTerrain = new Terrain::Terrain(mRendering.getScene(), new MWRender::TerrainStorage(), RV_Terrain, + Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); + Loading::ScopedLoad load(listener); + mTerrain = new Terrain::World(listener, mRendering.getScene(), new MWRender::TerrainStorage(), RV_Terrain, Settings::Manager::getBool("distant land", "Terrain"), Settings::Manager::getBool("shader", "Terrain")); mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"), Settings::Manager::getBool("split", "Shadows")); mTerrain->update(mRendering.getCamera()->getRealPosition()); + mTerrain->setLoadingListener(NULL); } mTerrain->setVisible(true); } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 45929f064..2d0813912 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -40,7 +40,7 @@ namespace sh namespace Terrain { - class Terrain; + class World; } namespace MWRender @@ -234,7 +234,7 @@ private: OcclusionQuery* mOcclusionQuery; - Terrain::Terrain* mTerrain; + Terrain::World* mTerrain; MWRender::Water *mWater; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 03e2ce623..372be8393 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -4,11 +4,10 @@ #include #include -#include "../mwworld/esmstore.hpp" - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/player.hpp" #include "sound_output.hpp" @@ -103,6 +102,7 @@ namespace MWSound SoundManager::~SoundManager() { + mUnderwaterSound.reset(); mActiveSounds.clear(); mMusic.reset(); mOutput.reset(); @@ -474,27 +474,32 @@ namespace MWSound void SoundManager::updateRegionSound(float duration) { - MWWorld::Ptr::CellStore *current = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); + static float sTimeToNextEnvSound = 0.0f; static int total = 0; static std::string regionName = ""; - static float timePassed = 0.0; + static float sTimePassed = 0.0; + MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Ptr player = world->getPlayer().getPlayer(); + const ESM::Cell *cell = player.getCell()->mCell; - //If the region has changed - timePassed += duration; - if(!current->mCell->isExterior() || timePassed < 10) + sTimePassed += duration; + if(!cell->isExterior() || sTimePassed < sTimeToNextEnvSound) return; - timePassed = 0; - if(regionName != current->mCell->mRegion) + float a = std::rand() / (double)RAND_MAX; + // NOTE: We should use the "Minimum Time Between Environmental Sounds" and + // "Maximum Time Between Environmental Sounds" fallback settings here. + sTimeToNextEnvSound = 5.0f*a + 15.0f*(1.0f-a); + sTimePassed = 0; + + if(regionName != cell->mRegion) { - regionName = current->mCell->mRegion; + regionName = cell->mRegion; total = 0; } - const ESM::Region *regn = - MWBase::Environment::get().getWorld()->getStore().get().search(regionName); - - if (regn == NULL) + const ESM::Region *regn = world->getStore().get().search(regionName); + if(regn == NULL) return; std::vector::const_iterator soundIter; @@ -550,15 +555,13 @@ namespace MWSound { env = Env_Underwater; //play underwater sound - //HACK: this sound is always played underwater, so set volume and pitch higher (it's then lowered) - //Currently not possible to play looping sound with no environment - if(!getSoundPlaying(MWWorld::Ptr(), "Underwater")) - playSound("Underwater", 1.11, 1.42 ,Play_TypeSfx, Play_Loop ); + if(!(mUnderwaterSound && mUnderwaterSound->isPlaying())) + mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Play_TypeSfx, Play_LoopNoEnv); } - else + else if(mUnderwaterSound) { - //no need to check if it's playing, stop sound does nothing in that case - stopSound("Underwater"); + mUnderwaterSound->stop(); + mUnderwaterSound.reset(); } mOutput->updateListener( diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 2450ba5c3..f62e62d50 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -44,6 +44,8 @@ namespace MWSound typedef std::map SoundMap; SoundMap mActiveSounds; + MWBase::SoundPtr mUnderwaterSound; + Ogre::Vector3 mListenerPos; Ogre::Vector3 mListenerDir; Ogre::Vector3 mListenerUp; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 8bb3d3c8d..0c145ab60 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -43,7 +43,8 @@ namespace MWWorld // 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); + if (iter != mList.end()) + mList.erase(iter); return; } diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 5a4f1db54..7703f2d23 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -5,6 +5,8 @@ #include +#include + namespace MWWorld { @@ -21,8 +23,10 @@ static bool isCacheableRecord(int id) return false; } -void ESMStore::load(ESM::ESMReader &esm) +void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) { + listener->setProgressRange(1000); + std::set missing; ESM::Dialogue *dialogue = 0; @@ -109,6 +113,7 @@ void ESMStore::load(ESM::ESMReader &esm) mIds[id] = n.val; } } + listener->setProgress(esm.getFileOffset() / (float)esm.getFileSize() * 1000); } /* This information isn't needed on screen. But keep the code around diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index d86faf766..ebb086cee 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -6,6 +6,11 @@ #include #include "store.hpp" +namespace Loading +{ + class Listener; +} + namespace MWWorld { class ESMStore @@ -158,7 +163,7 @@ namespace MWWorld mNpcs.insert(mPlayerTemplate); } - void load(ESM::ESMReader &esm); + void load(ESM::ESMReader &esm, Loading::Listener* listener); template const Store &get() const { diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 97aa7dffe..433fe0892 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -29,7 +29,7 @@ namespace MWWorld { static const float sMaxSlope = 60.0f; - static const float sStepSize = 30.0f; + static const float sStepSize = 32.0f; // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. static const int sMaxIterations = 8; @@ -48,16 +48,15 @@ namespace MWWorld OEngine::Physic::ActorTracer tracer, stepper; stepper.doTrace(colobj, position, position+Ogre::Vector3(0.0f,0.0f,sStepSize), engine); - if(stepper.mFraction == 0.0f) + if(stepper.mFraction < std::numeric_limits::epsilon()) return false; tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + velocity*remainingTime, engine); - if(tracer.mFraction < std::numeric_limits::epsilon() || - (tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) > sMaxSlope)) + if(tracer.mFraction < std::numeric_limits::epsilon()) return false; stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-Ogre::Vector3(0.0f,0.0f,sStepSize), engine); - if(getSlope(stepper.mPlaneNormal) <= sMaxSlope) + if(stepper.mFraction < 1.0f && getSlope(stepper.mPlaneNormal) <= sMaxSlope) { // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. position = stepper.mEndPos; @@ -257,7 +256,7 @@ namespace MWWorld return mEngine; } - std::pair PhysicsSystem::getFacedHandle (MWWorld::World& world, float queryDistance) + std::pair PhysicsSystem::getFacedHandle(float queryDistance) { Ray ray = mRender.getCamera()->getCameraToViewportRay(0.5, 0.5); @@ -267,8 +266,7 @@ namespace MWWorld btVector3 dir(dir_.x, dir_.y, dir_.z); btVector3 dest = origin + dir * queryDistance; - std::pair result; - /*auto*/ result = mEngine->rayTest(origin, dest); + std::pair result = mEngine->rayTest(origin, dest); result.second *= queryDistance; return std::make_pair (result.second, result.first); @@ -339,24 +337,6 @@ namespace MWWorld } - btVector3 PhysicsSystem::getRayPoint(float extent) - { - //get a ray pointing to the center of the viewport - Ray centerRay = mRender.getCamera()->getCameraToViewportRay( - mRender.getViewport()->getWidth()/2, - mRender.getViewport()->getHeight()/2); - btVector3 result(centerRay.getPoint(extent).x,centerRay.getPoint(extent).y,centerRay.getPoint(extent).z); - return result; - } - - btVector3 PhysicsSystem::getRayPoint(float extent, float mouseX, float mouseY) - { - //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).y,centerRay.getPoint(extent).z); - return result; - } - bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to, bool raycastingObjectOnly,bool ignoreHeightMap) { btVector3 _from, _to; diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index f76b4d29c..3dcd088f5 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -56,7 +56,7 @@ namespace MWWorld std::vector getCollisions(const MWWorld::Ptr &ptr); ///< get handles this object collides with Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr); - std::pair getFacedHandle (MWWorld::World& world, float queryDistance); + std::pair getFacedHandle(float queryDistance); std::pair getHitContact(const std::string &name, const Ogre::Vector3 &origin, const Ogre::Quaternion &orientation, @@ -64,10 +64,6 @@ namespace MWWorld std::vector < std::pair > getFacedHandles (float queryDistance); std::vector < std::pair > getFacedHandles (float mouseX, float mouseY, float queryDistance); - btVector3 getRayPoint(float extent); - btVector3 getRayPoint(float extent, float mouseX, float mouseY); - - // cast ray, return true if it hit something. if raycasringObjectOnlt is set to false, it ignores NPCs and objects with no collisions. bool castRay(const Ogre::Vector3& from, const Ogre::Vector3& to, bool raycastingObjectOnly = true,bool ignoreHeightMap = false); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index ee8973ae5..0c98ca504 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -25,13 +25,12 @@ namespace template void insertCellRefList(MWRender::RenderingManager& rendering, - T& cellRefList, MWWorld::CellStore &cell, MWWorld::PhysicsSystem& physics, bool rescale) + T& cellRefList, MWWorld::CellStore &cell, MWWorld::PhysicsSystem& physics, bool rescale, Loading::Listener* loadingListener) { if (!cellRefList.mList.empty()) { const MWWorld::Class& class_ = MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.mList.begin(), &cell)); - int current = 0; for (typename T::List::iterator it = cellRefList.mList.begin(); it != cellRefList.mList.end(); it++) { @@ -43,8 +42,6 @@ namespace it->mRef.mScale = 2; } - ++current; - if (it->mData.getCount() && it->mData.isEnabled()) { MWWorld::Ptr ptr (&*it, &cell); @@ -68,6 +65,8 @@ namespace std::cerr << error + e.what() << std::endl; } } + + loadingListener->increaseProgress(1); } } } @@ -117,7 +116,7 @@ namespace MWWorld mActiveCells.erase(*iter); } - void Scene::loadCell (Ptr::CellStore *cell) + void Scene::loadCell (Ptr::CellStore *cell, Loading::Listener* loadingListener) { // register local scripts MWBase::Environment::get().getWorld()->getLocalScripts().addCell (cell); @@ -150,7 +149,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); + insertCell (*cell, true, loadingListener); mRendering.cellAdded (cell); @@ -200,17 +199,15 @@ 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); + Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); + Loading::ScopedLoad load(loadingListener); // remove active MWBase::Environment::get().getMechanicsManager()->remove(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - std::string loadingExteriorText; - - loadingExteriorText = gmst.find ("sLoadingMessage3")->getString(); + std::string loadingExteriorText = "#{sLoadingMessage3}"; + loadingListener->setLabel(loadingExteriorText); CellStoreCollection::iterator active = mActiveCells.begin(); @@ -232,7 +229,6 @@ namespace MWWorld ++numUnload; } - int current = 0; active = mActiveCells.begin(); while (active!=mActiveCells.end()) { @@ -247,11 +243,10 @@ namespace MWWorld } } unloadCell (active++); - ++current; } - int numLoad = 0; - // get the number of cells to load + int refsToLoad = 0; + // get the number of refs to load for (int x=X-1; x<=X+1; ++x) for (int y=Y-1; y<=Y+1; ++y) { @@ -269,11 +264,12 @@ namespace MWWorld } if (iter==mActiveCells.end()) - ++numLoad; + refsToLoad += countRefs(*MWBase::Environment::get().getWorld()->getExterior(x, y)); } + loadingListener->setProgressRange(refsToLoad); + // Load cells - current = 0; for (int x=X-1; x<=X+1; ++x) for (int y=Y-1; y<=Y+1; ++y) { @@ -294,11 +290,7 @@ namespace MWWorld { CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y); - //Loading Exterior loading text - MWBase::Environment::get().getWindowManager ()->setLoadingProgress (loadingExteriorText, 0, current, numLoad); - - loadCell (cell); - ++current; + loadCell (cell, loadingListener); } } @@ -330,7 +322,7 @@ namespace MWWorld mCellChanged = true; - MWBase::Environment::get().getWindowManager ()->loadingDone (); + loadingListener->removeWallpaper(); } //We need the ogre renderer and a scene node. @@ -356,13 +348,14 @@ namespace MWWorld void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0.5); - const MWWorld::Store &gmst = - MWBase::Environment::get().getWorld()->getStore().get(); mRendering.enableTerrain(false); - std::string loadingInteriorText; - loadingInteriorText = gmst.find ("sLoadingMessage2")->getString(); + Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); + Loading::ScopedLoad load(loadingListener); + + std::string loadingInteriorText = "#{sLoadingMessage2}"; + loadingListener->setLabel(loadingInteriorText); CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(cellName); bool loadcell = (mCurrentCell == NULL); @@ -406,13 +399,15 @@ namespace MWWorld ++current; } + int refsToLoad = countRefs(*cell); + loadingListener->setProgressRange(refsToLoad); + // Load cell. std::cout << "cellName: " << cell->mCell->mName << std::endl; //Loading Interior loading text - MWBase::Environment::get().getWindowManager ()->setLoadingProgress (loadingInteriorText, 0, 0, 1); - loadCell (cell); + loadCell (cell, loadingListener); mCurrentCell = cell; @@ -429,7 +424,7 @@ namespace MWWorld mCellChanged = true; MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(0.5); - MWBase::Environment::get().getWindowManager ()->loadingDone (); + loadingListener->removeWallpaper(); } void Scene::changeToExteriorCell (const ESM::Position& position) @@ -454,30 +449,54 @@ namespace MWWorld mCellChanged = false; } - void Scene::insertCell (Ptr::CellStore &cell, bool rescale) + int Scene::countRefs (const Ptr::CellStore& cell) + { + return cell.mActivators.mList.size() + + cell.mPotions.mList.size() + + cell.mAppas.mList.size() + + cell.mArmors.mList.size() + + cell.mBooks.mList.size() + + cell.mClothes.mList.size() + + cell.mContainers.mList.size() + + cell.mDoors.mList.size() + + cell.mIngreds.mList.size() + + cell.mCreatureLists.mList.size() + + cell.mItemLists.mList.size() + + cell.mLights.mList.size() + + cell.mLockpicks.mList.size() + + cell.mMiscItems.mList.size() + + cell.mProbes.mList.size() + + cell.mRepairs.mList.size() + + cell.mStatics.mList.size() + + cell.mWeapons.mList.size() + + cell.mCreatures.mList.size() + + cell.mNpcs.mList.size(); + } + + void Scene::insertCell (Ptr::CellStore &cell, bool rescale, Loading::Listener* loadingListener) { // Loop through all references in the cell - 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.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.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); + insertCellRefList(mRendering, cell.mActivators, cell, *mPhysics, rescale, loadingListener); + insertCellRefList(mRendering, cell.mPotions, cell, *mPhysics, rescale, loadingListener); + insertCellRefList(mRendering, cell.mAppas, cell, *mPhysics, rescale, loadingListener); + insertCellRefList(mRendering, cell.mArmors, cell, *mPhysics, rescale, loadingListener); + insertCellRefList(mRendering, cell.mBooks, cell, *mPhysics, rescale, loadingListener); + insertCellRefList(mRendering, cell.mClothes, cell, *mPhysics, rescale, loadingListener); + insertCellRefList(mRendering, cell.mContainers, cell, *mPhysics, rescale, loadingListener); + insertCellRefList(mRendering, cell.mDoors, cell, *mPhysics, rescale, loadingListener); + insertCellRefList(mRendering, cell.mIngreds, cell, *mPhysics, rescale, loadingListener); + insertCellRefList(mRendering, cell.mCreatureLists, cell, *mPhysics, rescale, loadingListener); + insertCellRefList(mRendering, cell.mItemLists, cell, *mPhysics, rescale, loadingListener); + insertCellRefList(mRendering, cell.mLights, cell, *mPhysics, rescale, loadingListener); + insertCellRefList(mRendering, cell.mLockpicks, cell, *mPhysics, rescale, loadingListener); + insertCellRefList(mRendering, cell.mMiscItems, cell, *mPhysics, rescale, loadingListener); + insertCellRefList(mRendering, cell.mProbes, cell, *mPhysics, rescale, loadingListener); + insertCellRefList(mRendering, cell.mRepairs, cell, *mPhysics, rescale, loadingListener); + insertCellRefList(mRendering, cell.mStatics, cell, *mPhysics, rescale, loadingListener); + insertCellRefList(mRendering, cell.mWeapons, cell, *mPhysics, rescale, loadingListener); // 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); + insertCellRefList(mRendering, cell.mCreatures, cell, *mPhysics, rescale, loadingListener); + insertCellRefList(mRendering, cell.mNpcs, cell, *mPhysics, rescale, loadingListener); } void Scene::addObjectToScene (const Ptr& ptr) diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 3dfbd1045..e3edad352 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -56,7 +56,9 @@ namespace MWWorld void playerCellChange (CellStore *cell, const ESM::Position& position, bool adjustPlayerPos = true); - void insertCell (Ptr::CellStore &cell, bool rescale); + void insertCell (Ptr::CellStore &cell, bool rescale, Loading::Listener* loadingListener); + + int countRefs (const Ptr::CellStore& cell); public: @@ -66,7 +68,7 @@ namespace MWWorld void unloadCell (CellStoreCollection::iterator iter); - void loadCell (CellStore *cell); + void loadCell (CellStore *cell, Loading::Listener* loadingListener); void changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos); ///< Move from exterior to interior or from interior cell to a different diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 587b7847b..6f5dbe23f 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -167,6 +167,11 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa setFallbackWeather(blizzard,"blizzard"); } +WeatherManager::~WeatherManager() +{ + stopSounds(true); +} + void WeatherManager::setWeather(const String& weather, bool instant) { if (weather == mCurrentWeather && mNextWeather == "") diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index a2a07cec7..80cbe0418 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -120,6 +120,7 @@ namespace MWWorld { public: WeatherManager(MWRender::RenderingManager*,MWWorld::Fallback* fallback); + ~WeatherManager(); /** * Change the weather in the specified region diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a6489fc30..2b4b5d225 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -184,11 +184,14 @@ namespace MWWorld int idx = 0; // NOTE: We might need to reserve one more for the running game / save. mEsm.resize(master.size() + plugins.size()); + Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); + listener->loadingOn(); 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"; + listener->setLabel(masterPath.filename().string()); // This parses the ESM file ESM::ESMReader lEsm; @@ -197,7 +200,7 @@ namespace MWWorld lEsm.setGlobalReaderList(&mEsm); lEsm.open (masterPath.string()); mEsm[idx] = lEsm; - mStore.load (mEsm[idx]); + mStore.load (mEsm[idx], listener); } for (std::vector::size_type i = 0; i < plugins.size(); i++, idx++) @@ -205,6 +208,7 @@ namespace MWWorld boost::filesystem::path pluginPath (fileCollections.getCollection (".esp").getPath (plugins[i])); std::cout << "Loading ESP " << pluginPath.string() << "\n"; + listener->setLabel(pluginPath.filename().string()); // This parses the ESP file ESM::ESMReader lEsm; @@ -213,8 +217,9 @@ namespace MWWorld lEsm.setGlobalReaderList(&mEsm); lEsm.open (pluginPath.string()); mEsm[idx] = lEsm; - mStore.load (mEsm[idx]); + mStore.load (mEsm[idx], listener); } + listener->loadingOff(); // insert records that may not be present in all versions of MW if (mEsm[0].getFormat() == 0) @@ -761,7 +766,7 @@ namespace MWWorld std::pair result; if (!mRendering->occlusionQuerySupported()) - result = mPhysics->getFacedHandle (*this, getMaxActivationDistance ()); + result = mPhysics->getFacedHandle (getMaxActivationDistance ()); else result = std::make_pair (mFacedDistance, mFacedHandle); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index baf905aa7..04423dc6f 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -67,7 +67,11 @@ add_component_dir (translation ) add_component_dir (terrain - quadtreenode chunk terrain storage material + quadtreenode chunk world storage material + ) + +add_component_dir (loadinglistener + loadinglistener ) find_package(Qt4 COMPONENTS QtCore QtGui) diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index ff10a202c..edc724cd2 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -70,6 +70,11 @@ public: void openRaw(const std::string &file); + /// Get the file size. Make sure that the file has been opened! + size_t getFileSize() { return mEsm->size(); } + /// Get the current position in the file. Make sure that the file has been opened! + size_t getFileOffset() { return mEsm->tell(); } + // 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 diff --git a/components/loadinglistener/loadinglistener.hpp b/components/loadinglistener/loadinglistener.hpp new file mode 100644 index 000000000..483d52491 --- /dev/null +++ b/components/loadinglistener/loadinglistener.hpp @@ -0,0 +1,35 @@ +#ifndef COMPONENTS_LOADINGLISTENER_H +#define COMPONENTS_LOADINGLISTENER_H + +namespace Loading +{ + class Listener + { + public: + virtual void setLabel (const std::string& label) = 0; + + // Use ScopedLoad instead of using these directly + virtual void loadingOn() = 0; + virtual void loadingOff() = 0; + + /// Indicate that some progress has been made, without specifying how much + virtual void indicateProgress () = 0; + + virtual void setProgressRange (size_t range) = 0; + virtual void setProgress (size_t value) = 0; + virtual void increaseProgress (size_t increase) = 0; + + /// Indicate the scene is now ready to be shown + virtual void removeWallpaper() = 0; + }; + + // Used for stopping a loading sequence when the object goes out of scope + struct ScopedLoad + { + ScopedLoad(Listener* l) : mListener(l) { mListener->loadingOn(); } + ~ScopedLoad() { mListener->loadingOff(); } + Listener* mListener; + }; +} + +#endif diff --git a/components/terrain/chunk.cpp b/components/terrain/chunk.cpp index 87222af8b..ce2118cdb 100644 --- a/components/terrain/chunk.cpp +++ b/components/terrain/chunk.cpp @@ -4,7 +4,7 @@ #include #include "quadtreenode.hpp" -#include "terrain.hpp" +#include "world.hpp" #include "storage.hpp" namespace Terrain diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index ed5673877..ef2c61013 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -3,7 +3,7 @@ #include #include -#include "terrain.hpp" +#include "world.hpp" #include "chunk.hpp" #include "storage.hpp" @@ -13,6 +13,13 @@ using namespace Terrain; namespace { + int Log2( int n ) + { + assert(n > 0); + int targetlevel = 0; + while (n >>= 1) ++targetlevel; + return targetlevel; + } // Utility functions for neighbour finding algorithm ChildDirection reflect(ChildDirection dir, Direction dir2) @@ -132,7 +139,7 @@ namespace } } -QuadTreeNode::QuadTreeNode(Terrain* terrain, ChildDirection dir, float size, const Ogre::Vector2 ¢er, QuadTreeNode* parent) +QuadTreeNode::QuadTreeNode(World* terrain, ChildDirection dir, float size, const Ogre::Vector2 ¢er, QuadTreeNode* parent) : mSize(size) , mCenter(center) , mParent(parent) @@ -161,7 +168,7 @@ QuadTreeNode::QuadTreeNode(Terrain* terrain, ChildDirection dir, float size, con pos = mCenter - pos; mSceneNode->setPosition(Ogre::Vector3(pos.x*8192, pos.y*8192, 0)); - mLodLevel = log2(mSize); + mLodLevel = Log2(mSize); mMaterialGenerator = new MaterialGenerator(mTerrain->getShadersEnabled()); } @@ -220,7 +227,7 @@ const Ogre::AxisAlignedBox& QuadTreeNode::getBoundingBox() return mBounds; } -void QuadTreeNode::update(const Ogre::Vector3 &cameraPos) +void QuadTreeNode::update(const Ogre::Vector3 &cameraPos, Loading::Listener* loadingListener) { const Ogre::AxisAlignedBox& bounds = getBoundingBox(); if (bounds.isNull()) @@ -254,6 +261,9 @@ void QuadTreeNode::update(const Ogre::Vector3 &cameraPos) bool hadChunk = hasChunk(); + if (loadingListener) + loadingListener->indicateProgress(); + if (!distantLand && dist > 8192*2) { if (mIsActive) @@ -341,7 +351,7 @@ void QuadTreeNode::update(const Ogre::Vector3 &cameraPos) } assert(hasChildren() && "Leaf node's LOD needs to be 0"); for (int i=0; i<4; ++i) - mChildren[i]->update(cameraPos); + mChildren[i]->update(cameraPos, loadingListener); } } diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index fe646f3bf..9f6fb5d24 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -5,6 +5,8 @@ #include #include +#include + namespace Ogre { class Rectangle2D; @@ -12,7 +14,7 @@ namespace Ogre namespace Terrain { - class Terrain; + class World; class Chunk; class MaterialGenerator; @@ -46,7 +48,7 @@ namespace Terrain /// @param size size (in *cell* units!) /// @param center center (in *cell* units!) /// @param parent parent node - QuadTreeNode (Terrain* terrain, ChildDirection dir, float size, const Ogre::Vector2& center, QuadTreeNode* parent); + QuadTreeNode (World* terrain, ChildDirection dir, float size, const Ogre::Vector2& center, QuadTreeNode* parent); ~QuadTreeNode(); void setVisible(bool visible); @@ -93,10 +95,10 @@ namespace Terrain /// Get bounding box in local coordinates const Ogre::AxisAlignedBox& getBoundingBox(); - Terrain* getTerrain() { return mTerrain; } + World* getTerrain() { return mTerrain; } /// Adjust LODs for the given camera position, possibly splitting up chunks or merging them. - void update (const Ogre::Vector3& cameraPos); + void update (const Ogre::Vector3& cameraPos, Loading::Listener* loadingListener); /// Adjust index buffers of chunks to stitch together chunks of different LOD, so that cracks are avoided. /// Call after QuadTreeNode::update! @@ -146,7 +148,7 @@ namespace Terrain Chunk* mChunk; - Terrain* mTerrain; + World* mTerrain; Ogre::TexturePtr mCompositeMap; diff --git a/components/terrain/terrain.cpp b/components/terrain/world.cpp similarity index 92% rename from components/terrain/terrain.cpp rename to components/terrain/world.cpp index 1a88d63e4..711ebbc8f 100644 --- a/components/terrain/terrain.cpp +++ b/components/terrain/world.cpp @@ -1,4 +1,4 @@ -#include "terrain.hpp" +#include "world.hpp" #include #include @@ -7,6 +7,7 @@ #include #include +#include #include "storage.hpp" #include "quadtreenode.hpp" @@ -51,7 +52,8 @@ namespace namespace Terrain { - Terrain::Terrain(Ogre::SceneManager* sceneMgr, Storage* storage, int visibilityFlags, bool distantLand, bool shaders) + World::World(Loading::Listener* loadingListener, Ogre::SceneManager* sceneMgr, + Storage* storage, int visibilityFlags, bool distantLand, bool shaders) : mStorage(storage) , mMinBatchSize(1) , mMaxBatchSize(64) @@ -60,7 +62,11 @@ namespace Terrain , mDistantLand(distantLand) , mShaders(shaders) , mVisible(true) + , mLoadingListener(loadingListener) { + loadingListener->setLabel("Creating terrain"); + loadingListener->indicateProgress(); + mCompositeMapSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); Ogre::Camera* compositeMapCam = mCompositeMapSceneMgr->createCamera("a"); @@ -86,17 +92,20 @@ namespace Terrain mRootNode = new QuadTreeNode(this, Root, size, Ogre::Vector2(center.x, center.y), NULL); buildQuadTree(mRootNode); + loadingListener->indicateProgress(); mRootNode->initAabb(); + loadingListener->indicateProgress(); mRootNode->initNeighbours(); + loadingListener->indicateProgress(); } - Terrain::~Terrain() + World::~World() { delete mRootNode; delete mStorage; } - void Terrain::buildQuadTree(QuadTreeNode *node) + void World::buildQuadTree(QuadTreeNode *node) { float halfSize = node->getSize()/2.f; @@ -143,15 +152,15 @@ namespace Terrain node->markAsDummy(); } - void Terrain::update(const Ogre::Vector3& cameraPos) + void World::update(const Ogre::Vector3& cameraPos) { if (!mVisible) return; - mRootNode->update(cameraPos); + mRootNode->update(cameraPos, mLoadingListener); mRootNode->updateIndexBuffers(); } - Ogre::AxisAlignedBox Terrain::getWorldBoundingBox (const Ogre::Vector2& center) + Ogre::AxisAlignedBox World::getWorldBoundingBox (const Ogre::Vector2& center) { if (center.x > mBounds.getMaximum().x || center.x < mBounds.getMinimum().x @@ -165,7 +174,7 @@ namespace Terrain return box; } - Ogre::HardwareVertexBufferSharedPtr Terrain::getVertexBuffer(int numVertsOneSide) + Ogre::HardwareVertexBufferSharedPtr World::getVertexBuffer(int numVertsOneSide) { if (mUvBufferMap.find(numVertsOneSide) != mUvBufferMap.end()) { @@ -197,7 +206,7 @@ namespace Terrain return buffer; } - Ogre::HardwareIndexBufferSharedPtr Terrain::getIndexBuffer(int flags, size_t& numIndices) + Ogre::HardwareIndexBufferSharedPtr World::getIndexBuffer(int flags, size_t& numIndices) { if (mIndexBufferMap.find(flags) != mIndexBufferMap.end()) { @@ -358,31 +367,31 @@ namespace Terrain return buffer; } - void Terrain::renderCompositeMap(Ogre::TexturePtr target) + void World::renderCompositeMap(Ogre::TexturePtr target) { mCompositeMapRenderTarget->update(); target->getBuffer()->blit(mCompositeMapRenderTexture->getBuffer()); } - void Terrain::clearCompositeMapSceneManager() + void World::clearCompositeMapSceneManager() { mCompositeMapSceneMgr->destroyAllManualObjects(); mCompositeMapSceneMgr->clearScene(); } - float Terrain::getHeightAt(const Ogre::Vector3 &worldPos) + float World::getHeightAt(const Ogre::Vector3 &worldPos) { return mStorage->getHeightAt(worldPos); } - void Terrain::applyMaterials(bool shadows, bool splitShadows) + void World::applyMaterials(bool shadows, bool splitShadows) { mShadows = shadows; mSplitShadows = splitShadows; mRootNode->applyMaterials(); } - void Terrain::setVisible(bool visible) + void World::setVisible(bool visible) { if (visible && !mVisible) mSceneMgr->getRootSceneNode()->addChild(mRootSceneNode); @@ -392,7 +401,7 @@ namespace Terrain mVisible = visible; } - bool Terrain::getVisible() + bool World::getVisible() { return mVisible; } diff --git a/components/terrain/terrain.hpp b/components/terrain/world.hpp similarity index 92% rename from components/terrain/terrain.hpp rename to components/terrain/world.hpp index 4d329f9e1..b8c1b0a7d 100644 --- a/components/terrain/terrain.hpp +++ b/components/terrain/world.hpp @@ -6,6 +6,11 @@ #include #include +namespace Loading +{ + class Listener; +} + namespace Ogre { class Camera; @@ -24,10 +29,11 @@ namespace Terrain * Cracks at LOD transitions are avoided using stitching. * @note Multiple cameras are not supported yet */ - class Terrain + class World { public: /// @note takes ownership of \a storage + /// @param loadingListener Listener to update with progress /// @param sceneMgr scene manager to use /// @param storage Storage instance to get terrain data from (heights, normals, colors, textures..) /// @param visbilityFlags visibility flags for the created meshes @@ -35,8 +41,11 @@ namespace Terrain /// This is a temporary option until it can be streamlined. /// @param shaders Whether to use splatting shader, or multi-pass fixed function splatting. Shader is usually /// faster so this is just here for compatibility. - Terrain(Ogre::SceneManager* sceneMgr, Storage* storage, int visiblityFlags, bool distantLand, bool shaders); - ~Terrain(); + World(Loading::Listener* loadingListener, Ogre::SceneManager* sceneMgr, + Storage* storage, int visiblityFlags, bool distantLand, bool shaders); + ~World(); + + void setLoadingListener(Loading::Listener* loadingListener) { mLoadingListener = loadingListener; } bool getDistantLandEnabled() { return mDistantLand; } bool getShadersEnabled() { return mShaders; } @@ -84,6 +93,8 @@ namespace Terrain bool mSplitShadows; bool mVisible; + Loading::Listener* mLoadingListener; + QuadTreeNode* mRootNode; Ogre::SceneNode* mRootSceneNode; Storage* mStorage; diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index 5602946ff..931d6aca3 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -35,9 +35,20 @@ namespace SFO mSDLWindow = NULL; } - void InputWrapper::capture() + void InputWrapper::capture(bool windowEventsOnly) { + SDL_PumpEvents(); + SDL_Event evt; + + if (windowEventsOnly) + { + // During loading, just handle window events, and keep others for later + while (SDL_PeepEvents(&evt, 1, SDL_GETEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT)) + handleWindowEvent(evt); + return; + } + while(SDL_PollEvent(&evt)) { switch(evt.type) diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index 66bf60c7c..1bd8947a0 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -24,7 +24,7 @@ namespace SFO void setWindowEventCallback(WindowListener* listen) { mWindowListener = listen; } void setJoyEventCallback(JoyListener* listen) { mJoyListener = listen; } - void capture(); + void capture(bool windowEventsOnly); bool isModifierHeld(SDL_Keymod mod); bool isKeyDown(SDL_Scancode key); diff --git a/files/materials/water.shader b/files/materials/water.shader index a6d0a47e6..87e90a291 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -3,23 +3,28 @@ #define SIMPLE_WATER @shGlobalSettingBool(simple_water) - #if SIMPLE_WATER // --------------------------------------- SIMPLE WATER --------------------------------------------------- +#define FOG @shGlobalSettingBool(fog) + #ifdef SH_VERTEX_SHADER SH_BEGIN_PROGRAM shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) shVertexInput(float2, uv0) shOutput(float2, UV) - shOutput(float, depth) +#if FOG + shOutput(float, depth) +#endif SH_START_PROGRAM { shOutputPosition = shMatrixMult(wvp, shInputPosition); UV = uv0; +#if FOG depth = shOutputPosition.z; +#endif } #else @@ -38,8 +43,10 @@ shOutputColour(0).xyz = shSample(animatedTexture, UV * 15).xyz * float3(1.0, 1.0, 1.0); shOutputColour(0).w = 0.7; +#if FOG float fogValue = shSaturate((depth - fogParams.y) * fogParams.w); shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue); +#endif } #endif diff --git a/files/mygui/core_layouteditor.xml b/files/mygui/core_layouteditor.xml index db917b6ef..007b5e638 100644 --- a/files/mygui/core_layouteditor.xml +++ b/files/mygui/core_layouteditor.xml @@ -1,25 +1,25 @@ - - + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_alchemy_window.layout b/files/mygui/openmw_alchemy_window.layout index 2241813cf..4b15ac1bd 100644 --- a/files/mygui/openmw_alchemy_window.layout +++ b/files/mygui/openmw_alchemy_window.layout @@ -2,7 +2,7 @@ - + diff --git a/files/mygui/openmw_button.skin.xml b/files/mygui/openmw_button.skin.xml index 4f78f7125..e152a9112 100644 --- a/files/mygui/openmw_button.skin.xml +++ b/files/mygui/openmw_button.skin.xml @@ -62,7 +62,7 @@ - + diff --git a/files/mygui/openmw_chargen_birth.layout b/files/mygui/openmw_chargen_birth.layout index 75f741271..b368a6407 100644 --- a/files/mygui/openmw_chargen_birth.layout +++ b/files/mygui/openmw_chargen_birth.layout @@ -1,20 +1,20 @@ - + + - + - - + + - - + - + @@ -25,5 +25,6 @@ + diff --git a/files/mygui/openmw_chargen_class.layout b/files/mygui/openmw_chargen_class.layout index 6d159fe61..3c0348b66 100644 --- a/files/mygui/openmw_chargen_class.layout +++ b/files/mygui/openmw_chargen_class.layout @@ -1,66 +1,71 @@ - + + - + - - + + - + - - - - - - - - - - + + + + + + + - - - - - - - - - - + + + - - - - - - - - - - + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -71,5 +76,6 @@ + diff --git a/files/mygui/openmw_chargen_class_description.layout b/files/mygui/openmw_chargen_class_description.layout index 7050f1e3e..eaf754697 100644 --- a/files/mygui/openmw_chargen_class_description.layout +++ b/files/mygui/openmw_chargen_class_description.layout @@ -1,22 +1,22 @@ - + + - - - - - - + + + + - + + diff --git a/files/mygui/openmw_chargen_create_class.layout b/files/mygui/openmw_chargen_create_class.layout index 9677f438f..92382640b 100644 --- a/files/mygui/openmw_chargen_create_class.layout +++ b/files/mygui/openmw_chargen_create_class.layout @@ -1,14 +1,17 @@ - + + - - + + - + + + - + @@ -18,6 +21,7 @@ + @@ -30,35 +34,38 @@ - - + + + - - - - - + + + + + + - - - - - + + + + + + - + @@ -72,5 +79,6 @@ + diff --git a/files/mygui/openmw_chargen_generate_class_result.layout b/files/mygui/openmw_chargen_generate_class_result.layout index 9ee3e0701..f7178042f 100644 --- a/files/mygui/openmw_chargen_generate_class_result.layout +++ b/files/mygui/openmw_chargen_generate_class_result.layout @@ -1,26 +1,26 @@ - + - - + + - + - + - + diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index 0f63ba700..1290795ed 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -9,7 +9,7 @@ - + @@ -22,7 +22,7 @@ - + @@ -34,7 +34,7 @@ - + @@ -46,7 +46,7 @@ - + @@ -65,17 +65,17 @@ - + - + - + diff --git a/files/mygui/openmw_chargen_review.layout b/files/mygui/openmw_chargen_review.layout index 84b105bd0..5d18f4bff 100644 --- a/files/mygui/openmw_chargen_review.layout +++ b/files/mygui/openmw_chargen_review.layout @@ -1,10 +1,10 @@ - + - - + + @@ -17,27 +17,27 @@ - - - - + + + + - - - + + + - + - + @@ -46,57 +46,57 @@ - - + + - + - + - + - + - + - + - + @@ -105,13 +105,13 @@ - - - + + + - - + + diff --git a/files/mygui/openmw_chargen_select_attribute.layout b/files/mygui/openmw_chargen_select_attribute.layout index b847bcd3b..f0f72bb0f 100644 --- a/files/mygui/openmw_chargen_select_attribute.layout +++ b/files/mygui/openmw_chargen_select_attribute.layout @@ -10,14 +10,14 @@ - - - - - - - - + + + + + + + + diff --git a/files/mygui/openmw_chargen_select_skill.layout b/files/mygui/openmw_chargen_select_skill.layout index 90ae477e5..dc1798995 100644 --- a/files/mygui/openmw_chargen_select_skill.layout +++ b/files/mygui/openmw_chargen_select_skill.layout @@ -14,45 +14,45 @@ - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + diff --git a/files/mygui/openmw_confirmation_dialog.layout b/files/mygui/openmw_confirmation_dialog.layout index 024b8ab3b..47e1fd2b8 100644 --- a/files/mygui/openmw_confirmation_dialog.layout +++ b/files/mygui/openmw_confirmation_dialog.layout @@ -1,19 +1,19 @@ - + - - - + + + - + - + diff --git a/files/mygui/openmw_console.layout b/files/mygui/openmw_console.layout index a65e8b4f4..bfda40c68 100644 --- a/files/mygui/openmw_console.layout +++ b/files/mygui/openmw_console.layout @@ -2,7 +2,7 @@ - + @@ -12,7 +12,7 @@ - + diff --git a/files/mygui/openmw_console.skin.xml b/files/mygui/openmw_console.skin.xml index 3537bd662..219cce39a 100644 --- a/files/mygui/openmw_console.skin.xml +++ b/files/mygui/openmw_console.skin.xml @@ -1,30 +1,33 @@ + + + - - - + + + - - - - - - - - + + + - - - - + + + + + + + + + diff --git a/files/mygui/openmw_dialogue_window.layout b/files/mygui/openmw_dialogue_window.layout index 9d54f03d0..78daa0705 100644 --- a/files/mygui/openmw_dialogue_window.layout +++ b/files/mygui/openmw_dialogue_window.layout @@ -15,11 +15,11 @@ - + - - + + diff --git a/files/mygui/openmw_dialogue_window_skin.xml b/files/mygui/openmw_dialogue_window_skin.xml index d4b76daa7..4f68a90fa 100644 --- a/files/mygui/openmw_dialogue_window_skin.xml +++ b/files/mygui/openmw_dialogue_window_skin.xml @@ -8,11 +8,11 @@ - - - - - + + + + + diff --git a/files/mygui/openmw_edit.skin.xml b/files/mygui/openmw_edit.skin.xml index 76988a5be..b10854b19 100644 --- a/files/mygui/openmw_edit.skin.xml +++ b/files/mygui/openmw_edit.skin.xml @@ -21,12 +21,10 @@ + + - - - - - + @@ -39,9 +37,9 @@ - + - + diff --git a/files/mygui/openmw_hud_energybar.skin.xml b/files/mygui/openmw_hud_energybar.skin.xml index f64cb6ca0..f10908d7b 100644 --- a/files/mygui/openmw_hud_energybar.skin.xml +++ b/files/mygui/openmw_hud_energybar.skin.xml @@ -43,32 +43,32 @@ - - + + - - + + - - + + - - + + diff --git a/files/mygui/openmw_interactive_messagebox.layout b/files/mygui/openmw_interactive_messagebox.layout index 8d6b6dc34..d3ac1f8b5 100644 --- a/files/mygui/openmw_interactive_messagebox.layout +++ b/files/mygui/openmw_interactive_messagebox.layout @@ -3,16 +3,16 @@ - - - + + + - - + + - + diff --git a/files/mygui/openmw_journal_skin.xml b/files/mygui/openmw_journal_skin.xml index 9fc5e4c7f..ca6d309d7 100644 --- a/files/mygui/openmw_journal_skin.xml +++ b/files/mygui/openmw_journal_skin.xml @@ -2,9 +2,9 @@ - - - + + + diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index 54143f270..02c11c354 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -5,8 +5,8 @@ - - + + @@ -43,8 +43,8 @@ - - + + @@ -89,17 +89,17 @@ - - + + - + - - + + @@ -114,9 +114,9 @@ - - - + + + @@ -144,9 +144,9 @@ - - - + + + @@ -157,12 +157,12 @@ - - - - + + + + - + @@ -171,7 +171,7 @@ - + diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 1e4bba5ed..5fd3440f9 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -12,8 +12,7 @@ - - + diff --git a/files/mygui/openmw_messagebox.layout b/files/mygui/openmw_messagebox.layout index 3d91a289a..dfdb57648 100644 --- a/files/mygui/openmw_messagebox.layout +++ b/files/mygui/openmw_messagebox.layout @@ -2,17 +2,17 @@ - - - - + + + + - - + + diff --git a/files/mygui/openmw_pointer.xml b/files/mygui/openmw_pointer.xml index cf21037f8..a55a5453c 100644 --- a/files/mygui/openmw_pointer.xml +++ b/files/mygui/openmw_pointer.xml @@ -1,39 +1,39 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_progress.skin.xml b/files/mygui/openmw_progress.skin.xml index 635e40fb2..35114ffeb 100644 --- a/files/mygui/openmw_progress.skin.xml +++ b/files/mygui/openmw_progress.skin.xml @@ -17,7 +17,7 @@ - + @@ -25,43 +25,56 @@ - - + + - + - - + + - - + + - - + + - - - + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_stats_window.layout b/files/mygui/openmw_stats_window.layout index dec962f05..5ae3f96ca 100644 --- a/files/mygui/openmw_stats_window.layout +++ b/files/mygui/openmw_stats_window.layout @@ -219,7 +219,7 @@ - + diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index 6959c1f5b..6a1dea60b 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -4,46 +4,46 @@ - - - + + + - - - + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - + + + @@ -51,36 +51,36 @@ - - - - + + + + - - - - - + + + + + - - - - - + + + + + - + - - - + + + @@ -93,9 +93,9 @@ - - - + + + @@ -108,9 +108,9 @@ - - - + + + @@ -123,9 +123,9 @@ - - - + + + @@ -138,46 +138,46 @@ - + - - + + - - + + - - + + - - + + - - - + + + - - - + + + - - - + + + diff --git a/files/mygui/openmw_tooltips.layout b/files/mygui/openmw_tooltips.layout index bec6dd87c..624c133f2 100644 --- a/files/mygui/openmw_tooltips.layout +++ b/files/mygui/openmw_tooltips.layout @@ -200,7 +200,7 @@ - + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index e8861578f..22586716c 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -97,26 +97,26 @@ - + - + - + - + - + - + - + - + @@ -167,7 +167,7 @@ - + @@ -185,7 +185,7 @@ - + @@ -196,7 +196,7 @@ - + @@ -207,7 +207,7 @@ - + @@ -218,7 +218,7 @@ - + @@ -230,25 +230,25 @@ - + - + - + - + @@ -256,56 +256,56 @@ - + - + - + - + - + - + - + - + @@ -390,9 +390,9 @@ - - - + + + @@ -415,10 +415,10 @@ ------------------------------------------------------ --> - - - - + + + + @@ -555,10 +555,10 @@ - - - - + + + + @@ -692,10 +692,10 @@ - - - - + + + + @@ -835,9 +835,9 @@ - - - + + + diff --git a/files/opencs/raster/Info.png b/files/opencs/raster/Info.png new file mode 100644 index 000000000..d7bdad6cb Binary files /dev/null and b/files/opencs/raster/Info.png differ diff --git a/files/opencs/raster/LandTexture.png b/files/opencs/raster/LandTexture.png new file mode 100644 index 000000000..84f729098 Binary files /dev/null and b/files/opencs/raster/LandTexture.png differ diff --git a/files/opencs/raster/PathGrid.png b/files/opencs/raster/PathGrid.png new file mode 100644 index 000000000..23b6b84d7 Binary files /dev/null and b/files/opencs/raster/PathGrid.png differ diff --git a/files/opencs/raster/birthsign.png b/files/opencs/raster/birthsign.png new file mode 100644 index 000000000..8192d2ebf Binary files /dev/null and b/files/opencs/raster/birthsign.png differ diff --git a/files/opencs/raster/body-part.png b/files/opencs/raster/body-part.png index 333c5d523..4aa5dc02e 100644 Binary files a/files/opencs/raster/body-part.png and b/files/opencs/raster/body-part.png differ diff --git a/files/opencs/raster/cell.png b/files/opencs/raster/cell.png new file mode 100644 index 000000000..c4f00c1f0 Binary files /dev/null and b/files/opencs/raster/cell.png differ diff --git a/files/opencs/raster/class.png b/files/opencs/raster/class.png new file mode 100644 index 000000000..316380363 Binary files /dev/null and b/files/opencs/raster/class.png differ diff --git a/files/opencs/raster/enchantment.png b/files/opencs/raster/enchantment.png new file mode 100644 index 000000000..c90fb27ce Binary files /dev/null and b/files/opencs/raster/enchantment.png differ diff --git a/files/opencs/raster/faction.png b/files/opencs/raster/faction.png new file mode 100644 index 000000000..8ac1f5200 Binary files /dev/null and b/files/opencs/raster/faction.png differ diff --git a/files/opencs/raster/globvar.png b/files/opencs/raster/globvar.png new file mode 100644 index 000000000..646145f0f Binary files /dev/null and b/files/opencs/raster/globvar.png differ diff --git a/files/opencs/raster/land.png b/files/opencs/raster/land.png new file mode 100644 index 000000000..20dd321dd Binary files /dev/null and b/files/opencs/raster/land.png differ diff --git a/files/opencs/raster/landpaint.png b/files/opencs/raster/landpaint.png new file mode 100644 index 000000000..711c0d8f5 Binary files /dev/null and b/files/opencs/raster/landpaint.png differ diff --git a/files/opencs/raster/magic-effect.png b/files/opencs/raster/magic-effect.png new file mode 100644 index 000000000..e672ffccb Binary files /dev/null and b/files/opencs/raster/magic-effect.png differ diff --git a/files/opencs/raster/magicrabbit.png b/files/opencs/raster/magicrabbit.png new file mode 100644 index 000000000..d1d7c8270 Binary files /dev/null and b/files/opencs/raster/magicrabbit.png differ diff --git a/files/opencs/raster/map.png b/files/opencs/raster/map.png new file mode 100644 index 000000000..3653797cc Binary files /dev/null and b/files/opencs/raster/map.png differ diff --git a/files/opencs/raster/race.png b/files/opencs/raster/race.png new file mode 100644 index 000000000..94a2de696 Binary files /dev/null and b/files/opencs/raster/race.png differ diff --git a/files/opencs/raster/script.png b/files/opencs/raster/script.png new file mode 100644 index 000000000..297da4021 Binary files /dev/null and b/files/opencs/raster/script.png differ diff --git a/files/opencs/raster/skill.png b/files/opencs/raster/skill.png new file mode 100644 index 000000000..418f4f35c Binary files /dev/null and b/files/opencs/raster/skill.png differ diff --git a/files/opencs/raster/spell.png b/files/opencs/raster/spell.png new file mode 100644 index 000000000..69c897180 Binary files /dev/null and b/files/opencs/raster/spell.png differ diff --git a/files/opencs/scalable/referenceable-record/.directory b/files/opencs/scalable/referenceable-record/.directory index e2d80ed58..c633c38a9 100644 --- a/files/opencs/scalable/referenceable-record/.directory +++ b/files/opencs/scalable/referenceable-record/.directory @@ -1,5 +1,7 @@ [Dolphin] -PreviewsShown=true -Timestamp=2013,3,21,10,19,49 +GroupedSorting=true +SortFoldersFirst=false +Timestamp=2013,8,11,16,50,43 Version=3 -ViewMode=1 +ViewMode=2 +VisibleRoles=Compact_text,Compact_size diff --git a/files/opencs/scalable/referenceable-record/activator.svg b/files/opencs/scalable/referenceable-record/activator.svg index 0c6db59a7..e917d9332 100644 --- a/files/opencs/scalable/referenceable-record/activator.svg +++ b/files/opencs/scalable/referenceable-record/activator.svg @@ -23,18 +23,18 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="5.6568542" - inkscape:cx="5.7818736" - inkscape:cy="23.778975" + inkscape:zoom="2" + inkscape:cx="-35.165989" + inkscape:cy="-65.142411" inkscape:document-units="px" - inkscape:current-layer="g3891" + inkscape:current-layer="g3910" showgrid="false" showguides="true" inkscape:guide-bbox="true" inkscape:window-width="1280" - inkscape:window-height="994" + inkscape:window-height="1001" inkscape:window-x="0" - inkscape:window-y="30" + inkscape:window-y="23" inkscape:window-maximized="1" inkscape:snap-page="true" inkscape:snap-bbox="true" @@ -45,7 +45,7 @@ inkscape:object-paths="true" inkscape:snap-intersection-paths="false" inkscape:object-nodes="true" - inkscape:snap-global="true" + inkscape:snap-global="false" inkscape:snap-smooth-nodes="true" inkscape:snap-grids="false" inkscape:snap-nodes="true" /> @@ -867,7 +867,7 @@ xlink:href="#linearGradient3942" id="linearGradient3955" gradientUnits="userSpaceOnUse" - gradientTransform="translate(-183.1468,-158.28118)" + gradientTransform="translate(-445.4059,-219.9852)" x1="74.006111" y1="153.75172" x2="344.5" @@ -877,7 +877,7 @@ xlink:href="#linearGradient3880" id="radialGradient3957" gradientUnits="userSpaceOnUse" - gradientTransform="matrix(1,0,0,1.0000234,0,-0.00345228)" + gradientTransform="matrix(0.90336573,0,0,0.90338687,22.936413,14.223841)" cx="237.35278" cy="147.22479" fx="237.35278" @@ -888,7 +888,7 @@ xlink:href="#linearGradient3846" id="radialGradient3959" gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.43641683,0,0,0.43645606,205.85223,33.676924)" + gradientTransform="matrix(0.40004875,0,0,0.40008471,208.47728,43.13925)" cx="72.191498" cy="260.15875" fx="72.191498" @@ -1003,84 +1003,18 @@ - - - - - - - - - - - - - - - - + transform="matrix(10.683152,0,0,10.683152,-3645.2454,641.29516)"> - - - diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 0834a2cd1..912781240 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -279,27 +279,23 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& 0, Ogre::PF_A8R8G8B8, Ogre::TU_WRITE_ONLY); -} -void OgreRenderer::createScene(const std::string& camName, float fov, float nearClip) -{ - assert(mRoot); - assert(mWindow); - // Get the SceneManager, in this case a generic one mScene = mRoot->createSceneManager(ST_GENERIC); - // Create the camera - mCamera = mScene->createCamera(camName); - mCamera->setNearClipDistance(nearClip); - mCamera->setFOVy(Degree(fov)); + mFader = new Fader(mScene); + + mCamera = mScene->createCamera("cam"); // Create one viewport, entire window mView = mWindow->addViewport(mCamera); - // Alter the camera aspect ratio to match the viewport mCamera->setAspectRatio(Real(mView->getActualWidth()) / Real(mView->getActualHeight())); +} - mFader = new Fader(mScene); +void OgreRenderer::adjustCamera(float fov, float nearClip) +{ + mCamera->setNearClipDistance(nearClip); + mCamera->setFOVy(Degree(fov)); } void OgreRenderer::adjustViewport() diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index 9e83bf4f6..89edc567d 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -157,7 +157,7 @@ namespace OEngine void createWindow(const std::string &title, const WindowSettings& settings); /// Set up the scene manager, camera and viewport - void createScene(const std::string& camName="Camera",// Camera name + void adjustCamera( float fov=55, // Field of view angle float nearClip=5 // Near clip distance );