diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d6daf9f0..3f95f2d4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 25) +set (OPENMW_VERSION_MINOR 26) set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 5908deb90..92cabffff 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -24,7 +24,6 @@ set(LAUNCHER_HEADER graphicspage.hpp maindialog.hpp playpage.hpp - unshieldthread.hpp textslotmsgbox.hpp settings/gamesettings.hpp @@ -47,7 +46,6 @@ set(LAUNCHER_HEADER_MOC graphicspage.hpp maindialog.hpp playpage.hpp - unshieldthread.hpp textslotmsgbox.hpp utils/checkablemessagebox.hpp diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 1bbf7f897..9308c1d57 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -3,6 +3,11 @@ #include #include #include + +#ifdef __APPLE__ +// We need to do this because of Qt: https://bugreports.qt-project.org/browse/QTBUG-22154 +#define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ +#endif #include #include diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index dfe2d7413..f67f5edcf 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -3,6 +3,10 @@ #include #include +#ifdef __APPLE__ +// We need to do this because of Qt: https://bugreports.qt-project.org/browse/QTBUG-22154 +#define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ +#endif #include #include "maindialog.hpp" diff --git a/apps/launcher/unshieldthread.cpp b/apps/launcher/unshieldthread.cpp index ab9d984e1..6ddad7a21 100644 --- a/apps/launcher/unshieldthread.cpp +++ b/apps/launcher/unshieldthread.cpp @@ -216,7 +216,12 @@ namespace else { if(copy) - bfs::copy_file(dir->path(), to / dir->path().filename()); + { + bfs::path dest = to / dir->path().filename(); + if(bfs::exists(dest)) + bfs::remove_all(dest); + bfs::copy_file(dir->path(), dest); + } else bfs::rename(dir->path(), to / dir->path().filename()); } @@ -481,6 +486,7 @@ void UnshieldThread::run() UnshieldThread::UnshieldThread() { + unshield_set_log_level(0); mMorrowindDone = false; mTribunalDone = false; mBloodmoonDone = false; diff --git a/apps/launcher/unshieldthread.hpp b/apps/launcher/unshieldthread.hpp index b48d3d987..655cb5b53 100644 --- a/apps/launcher/unshieldthread.hpp +++ b/apps/launcher/unshieldthread.hpp @@ -7,7 +7,6 @@ #include - class UnshieldThread : public QThread { Q_OBJECT diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index ad7b5b19c..fe0415ac0 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -135,7 +135,7 @@ if(WIN32) set(QT_USE_QTMAIN TRUE) endif(WIN32) -find_package(Qt4 COMPONENTS QtCore QtGui QtXml QtXmlPatterns REQUIRED) +find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork QtXml QtXmlPatterns REQUIRED) include(${QT_USE_FILE}) qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index e05ebcdeb..e9a4a4089 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -2,17 +2,24 @@ #include "editor.hpp" #include +#include +#include #include "model/doc/document.hpp" #include "model/world/data.hpp" CS::Editor::Editor() : mViewManager (mDocumentManager) { + mIpcServerName = "org.openmw.OpenCS"; + connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ())); connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ())); + connect (&mViewManager, SIGNAL (editSettingsRequest()), this, SLOT (showSettings ())); - connect (&mStartup, SIGNAL (createDocument()), this, SLOT (createDocument ())); + connect (&mStartup, SIGNAL (createGame()), this, SLOT (createDocument ())); /// \todo split + connect (&mStartup, SIGNAL (createAddon()), this, SLOT (createDocument ())); connect (&mStartup, SIGNAL (loadDocument()), this, SLOT (loadDocument ())); + connect (&mStartup, SIGNAL (editConfig()), this, SLOT (showSettings ())); connect (&mFileDialog, SIGNAL(openFiles()), this, SLOT(openFiles())); connect (&mFileDialog, SIGNAL(createNewFile()), this, SLOT(createNewFile())); @@ -65,7 +72,7 @@ void CS::Editor::setupDataFiles() //load the settings into the userSettings instance. const QString settingFileName = "opencs.cfg"; CSMSettings::UserSettings::instance().loadSettings(settingFileName); - + } void CS::Editor::createDocument() @@ -114,6 +121,44 @@ void CS::Editor::createNewFile() mFileDialog.hide(); } +void CS::Editor::showStartup() +{ + if(mStartup.isHidden()) + mStartup.show(); + mStartup.raise(); + mStartup.activateWindow(); +} + +void CS::Editor::showSettings() +{ + if (mSettings.isHidden()) + mSettings.show(); + + mSettings.raise(); + mSettings.activateWindow(); +} + +bool CS::Editor::makeIPCServer() +{ + mServer = new QLocalServer(this); + + if(mServer->listen(mIpcServerName)) + { + connect(mServer, SIGNAL(newConnection()), this, SLOT(showStartup())); + return true; + } + + mServer->close(); + return false; +} + +void CS::Editor::connectToIPCServer() +{ + mClientSocket = new QLocalSocket(this); + mClientSocket->connectToServer(mIpcServerName); + mClientSocket->close(); +} + int CS::Editor::run() { mStartup.show(); diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 380e434c2..e32d7d8e5 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -2,15 +2,22 @@ #define CS_EDITOR_H #include +#include +#include +#include + #ifndef Q_MOC_RUN #include #endif + +#include "model/settings/usersettings.hpp" #include "model/doc/documentmanager.hpp" #include "view/doc/viewmanager.hpp" #include "view/doc/startup.hpp" #include "view/doc/filedialog.hpp" -#include "model/settings/usersettings.hpp" + +#include "view/settings/usersettingsdialog.hpp" namespace CS { @@ -22,6 +29,7 @@ namespace CS CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; CSVDoc::StartupDialogue mStartup; + CSVSettings::UserSettingsDialog mSettings; FileDialog mFileDialog; Files::ConfigurationManager mCfgMgr; @@ -35,6 +43,9 @@ namespace CS Editor(); + bool makeIPCServer(); + void connectToIPCServer(); + int run(); ///< \return error status @@ -45,6 +56,16 @@ namespace CS void loadDocument(); void openFiles(); void createNewFile(); + + void showStartup(); + + void showSettings(); + + private: + + QString mIpcServerName; + QLocalServer *mServer; + QLocalSocket *mClientSocket; }; } diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index 7f6f9302e..eddeb1983 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -39,5 +39,11 @@ int main(int argc, char *argv[]) CS::Editor editor; + if(!editor.makeIPCServer()) + { + editor.connectToIPCServer(); + return 0; + } + return editor.run(); } diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp index 5e580b6e1..8f4fcb70c 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,21 +47,33 @@ namespace CSMFilter std::string mString; double mNumber; - Token (Type type); + Token (Type type = Type_None); + + Token (Type type, const std::string& string); + ///< Non-string type that can also be interpreted as a string. Token (const std::string& string); Token (double number); operator bool() const; + + bool isString() const; }; Token::Token (Type type) : mType (type) {} + Token::Token (Type type, const std::string& string) : mType (type), mString (string) {} + Token::Token (const std::string& string) : mType (Type_String), mString (string) {} Token::Token (double number) : mType (Type_Number), mNumber (number) {} + bool Token::isString() const + { + return mType==Type_String || mType>=Type_Keyword_True; + } + Token::operator bool() const { return mType!=Type_None; @@ -89,7 +104,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 @@ -117,7 +132,7 @@ CSMFilter::Token CSMFilter::Parser::getStringToken() } if (string[0]=='"') - string = string.substr (1, string.size()-2); + return string.substr (1, string.size()-2); } return checkKeywords (string); @@ -171,15 +186,15 @@ 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) - return Token (static_cast (i+Token::Type_Keyword_True)); + if (sKeywords[i]==string || (string.size()==1 && sKeywords[i][0]==string[0])) + return Token (static_cast (i+Token::Type_Keyword_True), token.mString); return token; } @@ -208,9 +223,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 +236,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(); @@ -343,7 +363,7 @@ boost::shared_ptr CSMFilter::Parser::parseText() if (static_cast (token.mNumber)==token.mNumber) columnId = static_cast (token.mNumber); } - else if (token.mType==Token::Type_String) + else if (token.isString()) { columnId = CSMWorld::Columns::getId (token.mString); } @@ -365,7 +385,7 @@ boost::shared_ptr CSMFilter::Parser::parseText() // parse text pattern token = getNextToken(); - if (token.mType!=Token::Type_String) + if (!token.isString()) { error(); return boost::shared_ptr(); @@ -407,7 +427,7 @@ boost::shared_ptr CSMFilter::Parser::parseValue() if (static_cast (token.mNumber)==token.mNumber) columnId = static_cast (token.mNumber); } - else if (token.mType==Token::Type_String) + else if (token.isString()) { columnId = CSMWorld::Columns::getId (token.mString); } @@ -429,22 +449,22 @@ boost::shared_ptr CSMFilter::Parser::parseValue() // parse value double lower = 0; double upper = 0; - bool min = false; - bool max = false; + ValueNode::Type lowerType = ValueNode::Type_Open; + ValueNode::Type upperType = ValueNode::Type_Open; token = getNextToken(); if (token.mType==Token::Type_Number) { // single value - min = max = true; lower = upper = token.mNumber; + lowerType = upperType = ValueNode::Type_Closed; } else { // interval if (token.mType==Token::Type_OpenSquare) - min = true; + lowerType = ValueNode::Type_Closed; else if (token.mType!=Token::Type_CloseSquare && token.mType!=Token::Type_Open) { error(); @@ -453,17 +473,23 @@ boost::shared_ptr CSMFilter::Parser::parseValue() token = getNextToken(); - if (token.mType!=Token::Type_Number) + if (token.mType==Token::Type_Number) { - error(); - return boost::shared_ptr(); + lower = token.mNumber; + + token = getNextToken(); + + if (token.mType!=Token::Type_Comma) + { + error(); + return boost::shared_ptr(); + } } - - lower = token.mNumber; - - token = getNextToken(); - - if (token.mType!=Token::Type_Comma) + else if (token.mType==Token::Type_Comma) + { + lowerType = ValueNode::Type_Infinite; + } + else { error(); return boost::shared_ptr(); @@ -471,18 +497,20 @@ boost::shared_ptr CSMFilter::Parser::parseValue() token = getNextToken(); - if (token.mType!=Token::Type_Number) + if (token.mType==Token::Type_Number) { - error(); - return boost::shared_ptr(); + upper = token.mNumber; + + token = getNextToken(); } - - upper = token.mNumber; - - token = getNextToken(); + else + upperType = ValueNode::Type_Infinite; if (token.mType==Token::Type_CloseSquare) - max = true; + { + if (upperType!=ValueNode::Type_Infinite) + upperType = ValueNode::Type_Closed; + } else if (token.mType!=Token::Type_OpenSquare && token.mType!=Token::Type_Close) { error(); @@ -498,7 +526,7 @@ boost::shared_ptr CSMFilter::Parser::parseValue() return boost::shared_ptr(); } - return boost::shared_ptr (new ValueNode (columnId, lower, upper, min, max)); + return boost::shared_ptr (new ValueNode (columnId, lowerType, upperType, lower, upper)); } void CSMFilter::Parser::error() @@ -506,9 +534,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 +545,67 @@ 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; + } + // We do not use isString() here, because there could be a pre-defined filter with an ID that is + // equal a filter keyword. + 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/filter/textnode.cpp b/apps/opencs/model/filter/textnode.cpp index 9987c66d2..f3d98ce53 100644 --- a/apps/opencs/model/filter/textnode.cpp +++ b/apps/opencs/model/filter/textnode.cpp @@ -28,13 +28,34 @@ bool CSMFilter::TextNode::test (const CSMWorld::IdTable& table, int row, QVariant data = table.data (index); - if (data.type()!=QVariant::String) + QString string; + + if (data.type()==QVariant::String) + { + string = data.toString(); + } + else if (data.type()==QVariant::Int || data.type()==QVariant::UInt || + CSMWorld::Columns::hasEnums (static_cast (mColumnId))) + { + int value = data.toInt(); + + std::vector enums = + CSMWorld::Columns::getEnums (static_cast (mColumnId)); + + if (value>=0 && value (enums.size())) + string = QString::fromUtf8 (enums[value].c_str()); + } + else if (data.type()==QVariant::Bool) + { + string = data.toBool() ? "true" : " false"; + } + else return false; /// \todo make pattern syntax configurable QRegExp regExp (QString::fromUtf8 (mText.c_str()), Qt::CaseInsensitive); - return regExp.exactMatch (data.toString()); + return regExp.exactMatch (string); } std::vector CSMFilter::TextNode::getReferencedColumns() const diff --git a/apps/opencs/model/filter/valuenode.cpp b/apps/opencs/model/filter/valuenode.cpp index f6cb20e4c..7eeb6beab 100644 --- a/apps/opencs/model/filter/valuenode.cpp +++ b/apps/opencs/model/filter/valuenode.cpp @@ -7,10 +7,9 @@ #include "../world/columns.hpp" #include "../world/idtable.hpp" -CSMFilter::ValueNode::ValueNode (int columnId, - double lower, double upper, bool min, bool max) -: mColumnId (columnId), mLower (lower), mUpper (upper), mMin (min), mMax (max) -{} +CSMFilter::ValueNode::ValueNode (int columnId, Type lowerType, Type upperType, + double lower, double upper) +: mColumnId (columnId), mLowerType (lowerType), mUpperType (upperType), mLower (lower), mUpper (upper){} bool CSMFilter::ValueNode::test (const CSMWorld::IdTable& table, int row, const std::map& columns) const @@ -33,10 +32,21 @@ bool CSMFilter::ValueNode::test (const CSMWorld::IdTable& table, int row, double value = data.toDouble(); - if (mLower==mUpper && mMin && mMax) - return value==mLower; + switch (mLowerType) + { + case Type_Closed: if (value=mLower : value>mLower) && (mMax ? value<=mUpper : valuemUpper) return false; break; + case Type_Open: if (value>=mUpper) return false; break; + case Type_Infinite: break; + } + + return true; } std::vector CSMFilter::ValueNode::getReferencedColumns() const @@ -60,10 +70,26 @@ std::string CSMFilter::ValueNode::toString (bool numericColumns) const stream << ", \""; - if (mLower==mUpper && mMin && mMax) + if (mLower==mUpper && mLowerType!=Type_Infinite && mUpperType!=Type_Infinite) stream << mLower; else - stream << (mMin ? "[" : "(") << mLower << ", " << mUpper << (mMax ? "]" : ")"); + { + switch (mLowerType) + { + case Type_Closed: stream << "[" << mLower; break; + case Type_Open: stream << "(" << mLower; break; + case Type_Infinite: stream << "("; break; + } + + stream << ", "; + + switch (mUpperType) + { + case Type_Closed: stream << mUpper << "]"; break; + case Type_Open: stream << mUpper << ")"; break; + case Type_Infinite: stream << ")"; break; + } + } stream << ")"; diff --git a/apps/opencs/model/filter/valuenode.hpp b/apps/opencs/model/filter/valuenode.hpp index faaa1e2ff..b1050709d 100644 --- a/apps/opencs/model/filter/valuenode.hpp +++ b/apps/opencs/model/filter/valuenode.hpp @@ -7,16 +7,25 @@ namespace CSMFilter { class ValueNode : public LeafNode { + public: + + enum Type + { + Type_Closed, Type_Open, Type_Infinite + }; + + private: + int mColumnId; std::string mText; double mLower; double mUpper; - bool mMin; - bool mMax; + Type mLowerType; + Type mUpperType; public: - ValueNode (int columnId, double lower, double upper, bool min, bool max); + ValueNode (int columnId, Type lowerType, Type upperType, double lower, double upper); virtual bool test (const CSMWorld::IdTable& table, int row, const std::map& columns) const; 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..5616a4a48 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -3,6 +3,8 @@ #include +#include "universalid.hpp" + namespace CSMWorld { namespace Columns @@ -144,6 +146,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" }, @@ -195,4 +198,104 @@ int CSMWorld::Columns::getId (const std::string& name) return sNames[i].mId; return -1; +} + +namespace +{ + static const char *sSpecialisations[] = + { + "Combat", "Magic", "Stealth", 0 + }; + + static const char *sAttributes[] = + { + "Strength", "Intelligence", "Willpower", "Agility", "Speed", "Endurance", "Personality", + "Luck", 0 + }; + + static const char *sSpellTypes[] = + { + "Spell", "Ability", "Blight", "Disease", "Curse", "Power", 0 + }; + + static const char *sApparatusTypes[] = + { + "Mortar & Pestle", "Albemic", "Calcinator", "Retort", 0 + }; + + static const char *sArmorTypes[] = + { + "Helmet", "Cuirass", "Left Pauldron", "Right Pauldron", "Greaves", "Boots", "Left Gauntlet", + "Right Gauntlet", "Shield", "Left Bracer", "Right Bracer", 0 + }; + + static const char *sClothingTypes[] = + { + "Pants", "Shoes", "Shirt", "Belt", "Robe", "Right Glove", "Left Glove", "Skirt", "Ring", + "Amulet", 0 + }; + + static const char *sCreatureTypes[] = + { + "Creature", "Deadra", "Undead", "Humanoid", 0 + }; + + static const char *sWeaponTypes[] = + { + "Short Blade 1H", "Long Blade 1H", "Long Blade 2H", "Blunt 1H", "Blunt 2H Close", + "Blunt 2H Wide", "Spear 2H", "Axe 1H", "Axe 2H", "Bow", "Crossbow", "Thrown", "Arrow", + "Bolt", 0 + }; + + static const char *sModificationEnums[] = + { + "Base", "Modified", "Added", "Deleted", "Deleted", 0 + }; + + static const char *sVarTypeEnums[] = + { + "unknown", "none", "short", "integer", "long", "float", "string", 0 + }; + + const char **getEnumNames (CSMWorld::Columns::ColumnId column) + { + switch (column) + { + case CSMWorld::Columns::ColumnId_Specialisation: return sSpecialisations; + case CSMWorld::Columns::ColumnId_Attribute: return sAttributes; + case CSMWorld::Columns::ColumnId_SpellType: return sSpellTypes; + case CSMWorld::Columns::ColumnId_ApparatusType: return sApparatusTypes; + case CSMWorld::Columns::ColumnId_ArmorType: return sArmorTypes; + case CSMWorld::Columns::ColumnId_ClothingType: return sClothingTypes; + case CSMWorld::Columns::ColumnId_CreatureType: return sCreatureTypes; + case CSMWorld::Columns::ColumnId_WeaponType: return sWeaponTypes; + case CSMWorld::Columns::ColumnId_Modification: return sModificationEnums; + case CSMWorld::Columns::ColumnId_ValueType: return sVarTypeEnums; + + default: return 0; + } + } +} + +bool CSMWorld::Columns::hasEnums (ColumnId column) +{ + return getEnumNames (column)!=0 || column==ColumnId_RecordType; +} + +std::vector CSMWorld::Columns::getEnums (ColumnId column) +{ + std::vector enums; + + if (const char **table = getEnumNames (column)) + for (int i=0; table[i]; ++i) + enums.push_back (table[i]); + else if (column==ColumnId_RecordType) + { + enums.push_back (""); // none + + for (int i=UniversalId::Type_None+1; i (i)).getTypeName()); + } + + return enums; } \ No newline at end of file diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 28da60e93..69b20583a 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -2,6 +2,7 @@ #define CSM_WOLRD_COLUMNS_H #include +#include namespace CSMWorld { @@ -138,6 +139,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. @@ -179,6 +181,11 @@ namespace CSMWorld int getId (const std::string& name); ///< Will return -1 for an invalid name. + + bool hasEnums (ColumnId column); + + std::vector getEnums (ColumnId column); + ///< Returns an empty vector, if \æ column isn't an enum type column. } } 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/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 085817753..696aeefaa 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -6,10 +6,6 @@ #include "ref.hpp" #include "cell.hpp" -CSMWorld::RefCollection::RefCollection (Collection& cells) -: mCells (cells), mNextId (0) -{} - void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base) { Record cell = mCells.getRecord (cellIndex); diff --git a/apps/opencs/model/world/refcollection.hpp b/apps/opencs/model/world/refcollection.hpp index 895315a17..b5f8c8064 100644 --- a/apps/opencs/model/world/refcollection.hpp +++ b/apps/opencs/model/world/refcollection.hpp @@ -16,8 +16,10 @@ namespace CSMWorld int mNextId; public: - - RefCollection (Collection& cells); + // MSVC needs the constructor for a class inheriting a template to be defined in header + RefCollection (Collection& cells) + : mCells (cells), mNextId (0) + {} void load (ESM::ESMReader& reader, int cellIndex, bool base); ///< Load a sequence of references. diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 42ebd1f80..d360fde8f 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -80,7 +80,7 @@ namespace { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Static, "Static", ":./static.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Weapon, "Weapon", ":./weapon.png" }, { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Reference", 0 }, - + { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Filter, "Filter", 0 }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; @@ -90,8 +90,6 @@ namespace { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; - - static const unsigned int IDARG_SIZE = sizeof (sIdArg) / sizeof (TypeData); } CSMWorld::UniversalId::UniversalId (const std::string& universalId) @@ -151,6 +149,22 @@ CSMWorld::UniversalId::UniversalId (Type type) : mArgumentType (ArgumentType_Non return; } + for (int i=0; sIdArg[i].mName; ++i) + if (type==sIdArg[i].mType) + { + mArgumentType = ArgumentType_Id; + mClass = sIdArg[i].mClass; + return; + } + + for (int i=0; sIndexArg[i].mName; ++i) + if (type==sIndexArg[i].mType) + { + mArgumentType = ArgumentType_Index; + mClass = sIndexArg[i].mClass; + return; + } + throw std::logic_error ("invalid argument-less UniversalId type"); } @@ -293,25 +307,6 @@ std::vector CSMWorld::UniversalId::listReferenceabl return list; } -std::pair CSMWorld::UniversalId::getIdArgPair (unsigned int index) -{ - std::pair retPair; - - if ( index < IDARG_SIZE ) - { - retPair.first = sIdArg[index].mType; - retPair.second = sIdArg[index].mName; - } - - return retPair; -} - -unsigned int CSMWorld::UniversalId::getIdArgSize() -{ - return IDARG_SIZE; -} - - bool CSMWorld::operator== (const CSMWorld::UniversalId& left, const CSMWorld::UniversalId& right) { return left.isEqual (right); diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 8042c3dfd..aa0cdacc0 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -34,7 +34,7 @@ namespace CSMWorld enum Type { - Type_None, + Type_None = 0, Type_Globals, Type_Global, Type_VerificationResults, @@ -89,6 +89,8 @@ namespace CSMWorld Type_Filters }; + enum { NumberOfTypes = Type_Filters+1 }; + private: Class mClass; @@ -102,7 +104,6 @@ namespace CSMWorld UniversalId (const std::string& universalId); UniversalId (Type type = Type_None); - ///< Using a type for a non-argument-less UniversalId will throw an exception. UniversalId (Type type, const std::string& id); ///< Using a type for a non-ID-argument UniversalId will throw an exception. @@ -134,9 +135,6 @@ namespace CSMWorld ///< Will return an empty string, if no icon is available. static std::vector listReferenceableTypes(); - - static std::pair getIdArgPair (unsigned int index); - static unsigned int getIdArgSize (); }; bool operator== (const UniversalId& left, const UniversalId& right); diff --git a/apps/opencs/view/doc/startup.cpp b/apps/opencs/view/doc/startup.cpp index 6c1e74058..4cc64f2df 100644 --- a/apps/opencs/view/doc/startup.cpp +++ b/apps/opencs/view/doc/startup.cpp @@ -3,21 +3,106 @@ #include #include -#include +#include #include #include +#include +#include +#include +#include -CSVDoc::StartupDialogue::StartupDialogue() +QPushButton *CSVDoc::StartupDialogue::addButton (const QString& label, const QIcon& icon) { - QHBoxLayout *layout = new QHBoxLayout (this); + int column = mColumn--; - QPushButton *createDocument = new QPushButton ("new", this); - connect (createDocument, SIGNAL (clicked()), this, SIGNAL (createDocument())); - layout->addWidget (createDocument); + QPushButton *button = new QPushButton (this); - QPushButton *loadDocument = new QPushButton ("load", this); + button->setIcon (QIcon (icon)); + + button->setSizePolicy (QSizePolicy (QSizePolicy::Preferred, QSizePolicy::Preferred)); + + mLayout->addWidget (button, 0, column); + + mLayout->addWidget (new QLabel (label, this), 1, column, Qt::AlignCenter); + + int width = mLayout->itemAtPosition (1, column)->widget()->sizeHint().width(); + + if (width>mWidth) + mWidth = width; + + return button; +} + + +QWidget *CSVDoc::StartupDialogue::createButtons() +{ + QWidget *widget = new QWidget (this); + + mLayout = new QGridLayout (widget); + + /// \todo add icons + QPushButton *loadDocument = addButton ("Edit A Content File", QIcon (":startup/edit-content")); connect (loadDocument, SIGNAL (clicked()), this, SIGNAL (loadDocument())); - layout->addWidget (loadDocument); + + QPushButton *createAddon = addButton ("Create A New Addon", QIcon (":startup/create-addon")); + connect (createAddon, SIGNAL (clicked()), this, SIGNAL (createAddon())); + + QPushButton *createGame = addButton ("Create A New Game", QIcon (":startup/create-game")); + connect (createGame, SIGNAL (clicked()), this, SIGNAL (createGame())); + + for (int i=0; i<3; ++i) + mLayout->setColumnMinimumWidth (i, mWidth); + + mLayout->setRowMinimumHeight (0, mWidth); + + mLayout->setSizeConstraint (QLayout::SetMinimumSize); + mLayout->setHorizontalSpacing (32); + + mLayout->setContentsMargins (16, 16, 16, 8); + + loadDocument->setIconSize (QSize (mWidth, mWidth)); + createGame->setIconSize (QSize (mWidth, mWidth)); + createAddon->setIconSize (QSize (mWidth, mWidth)); + + widget->setLayout (mLayout); + + return widget; +} + +QWidget *CSVDoc::StartupDialogue::createTools() +{ + QWidget *widget = new QWidget (this); + + QHBoxLayout *layout = new QHBoxLayout (widget); + layout->setDirection (QBoxLayout::RightToLeft); + layout->setContentsMargins (4, 4, 4, 4); + + QPushButton *config = new QPushButton (widget); + + config->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); + config->setIcon (QIcon (":startup/configure")); + + layout->addWidget (config); + + layout->addWidget (new QWidget, 1); // dummy widget; stops buttons from taking all the space + + widget->setLayout (layout); + + connect (config, SIGNAL (clicked()), this, SIGNAL (editConfig())); + + return widget; +} + +CSVDoc::StartupDialogue::StartupDialogue() : mWidth (0), mColumn (2) +{ + setWindowTitle ("Open CS"); + + QVBoxLayout *layout = new QVBoxLayout (this); + + layout->setContentsMargins (0, 0, 0, 0); + + layout->addWidget (createButtons()); + layout->addWidget (createTools()); setLayout (layout); diff --git a/apps/opencs/view/doc/startup.hpp b/apps/opencs/view/doc/startup.hpp index f24d2a64b..f059a44e5 100644 --- a/apps/opencs/view/doc/startup.hpp +++ b/apps/opencs/view/doc/startup.hpp @@ -3,21 +3,43 @@ #include +class QGridLayout; +class QString; +class QPushButton; +class QWidget; +class QIcon; + namespace CSVDoc { class StartupDialogue : public QWidget { Q_OBJECT + private: + + int mWidth; + int mColumn; + QGridLayout *mLayout; + + QPushButton *addButton (const QString& label, const QIcon& icon); + + QWidget *createButtons(); + + QWidget *createTools(); + public: StartupDialogue(); signals: - void createDocument(); + void createGame(); + + void createAddon(); void loadDocument(); + + void editConfig(); }; } diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 6801ea20d..ab175872f 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -67,7 +67,7 @@ void CSVDoc::View::setupEditMenu() edit->addAction (mRedo); QAction *userSettings = new QAction (tr ("&Preferences"), this); - connect (userSettings, SIGNAL (triggered()), this, SLOT (showUserSettings())); + connect (userSettings, SIGNAL (triggered()), this, SIGNAL (editSettingsRequest())); edit->addAction (userSettings); } @@ -415,13 +415,6 @@ void CSVDoc::View::exit() emit exitApplicationRequest (this); } -void CSVDoc::View::showUserSettings() -{ - CSVSettings::UserSettingsDialog *settingsDialog = new CSVSettings::UserSettingsDialog(this); - - settingsDialog->show(); -} - void CSVDoc::View::resizeViewWidth (int width) { if (width >= 0) diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 56c0b3edd..41e26a6ba 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -112,6 +112,8 @@ namespace CSVDoc void exitApplicationRequest (CSVDoc::View *view); + void editSettingsRequest(); + public slots: void addSubView (const CSMWorld::UniversalId& id); @@ -160,8 +162,6 @@ namespace CSVDoc void addFiltersSubView(); - void showUserSettings(); - void toggleShowStatusBar (bool show); }; } diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 6d06e4248..984c81937 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -8,6 +8,7 @@ #include "../../model/doc/documentmanager.hpp" #include "../../model/doc/document.hpp" +#include "../../model/world/columns.hpp" #include "../world/util.hpp" #include "../world/enumdelegate.hpp" @@ -43,51 +44,6 @@ void CSVDoc::ViewManager::updateIndices() CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) : mDocumentManager (documentManager), mExitOnSaveStateChange(false), mUserWarned(false) { - static const char *sSpecialisations[] = - { - "Combat", "Magic", "Stealth", 0 - }; - - static const char *sAttributes[] = - { - "Strength", "Intelligence", "Willpower", "Agility", "Speed", "Endurance", "Personality", - "Luck", 0 - }; - - static const char *sSpellTypes[] = - { - "Spell", "Ability", "Blight", "Disease", "Curse", "Power", 0 - }; - - static const char *sApparatusTypes[] = - { - "Mortar & Pestle", "Albemic", "Calcinator", "Retort", 0 - }; - - static const char *sArmorTypes[] = - { - "Helmet", "Cuirass", "Left Pauldron", "Right Pauldron", "Greaves", "Boots", "Left Gauntlet", - "Right Gauntlet", "Shield", "Left Bracer", "Right Bracer", 0 - }; - - static const char *sClothingTypes[] = - { - "Pants", "Shoes", "Shirt", "Belt", "Robe", "Right Glove", "Left Glove", "Skirt", "Ring", - "Amulet", 0 - }; - - static const char *sCreatureTypes[] = - { - "Creature", "Deadra", "Undead", "Humanoid", 0 - }; - - static const char *sWeaponTypes[] = - { - "Short Blade 1H", "Long Blade 1H", "Long Blade 2H", "Blunt 1H", "Blunt 2H Close", - "Blunt 2H Wide", "Spear 2H", "Axe 1H", "Axe 2H", "Bow", "Crossbow", "Thrown", "Arrow", - "Bolt", 0 - }; - mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType, @@ -96,38 +52,37 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType, new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float)); - mDelegateFactories->add (CSMWorld::ColumnBase::Display_Specialisation, - new CSVWorld::EnumDelegateFactory (sSpecialisations)); - - mDelegateFactories->add (CSMWorld::ColumnBase::Display_Attribute, - new CSVWorld::EnumDelegateFactory (sAttributes, true)); - - mDelegateFactories->add (CSMWorld::ColumnBase::Display_SpellType, - new CSVWorld::EnumDelegateFactory (sSpellTypes)); - - mDelegateFactories->add (CSMWorld::ColumnBase::Display_ApparatusType, - new CSVWorld::EnumDelegateFactory (sApparatusTypes)); - - mDelegateFactories->add (CSMWorld::ColumnBase::Display_ArmorType, - new CSVWorld::EnumDelegateFactory (sArmorTypes)); - - mDelegateFactories->add (CSMWorld::ColumnBase::Display_ClothingType, - new CSVWorld::EnumDelegateFactory (sClothingTypes)); - - mDelegateFactories->add (CSMWorld::ColumnBase::Display_CreatureType, - new CSVWorld::EnumDelegateFactory (sCreatureTypes)); - - mDelegateFactories->add (CSMWorld::ColumnBase::Display_WeaponType, - new CSVWorld::EnumDelegateFactory (sWeaponTypes)); - mDelegateFactories->add (CSMWorld::ColumnBase::Display_RecordState, - new CSVWorld::RecordStatusDelegateFactory() ); + new CSVWorld::RecordStatusDelegateFactory()); mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType, - new CSVWorld::RefIdTypeDelegateFactory() ); + new CSVWorld::RefIdTypeDelegateFactory()); + + struct Mapping + { + CSMWorld::ColumnBase::Display mDisplay; + CSMWorld::Columns::ColumnId mColumnId; + bool mAllowNone; + }; + + static const Mapping sMapping[] = + { + { CSMWorld::ColumnBase::Display_Specialisation, CSMWorld::Columns::ColumnId_Specialisation, false }, + { CSMWorld::ColumnBase::Display_Attribute, CSMWorld::Columns::ColumnId_Attribute, true }, + { CSMWorld::ColumnBase::Display_SpellType, CSMWorld::Columns::ColumnId_SpellType, false }, + { CSMWorld::ColumnBase::Display_ApparatusType, CSMWorld::Columns::ColumnId_ApparatusType, false }, + { CSMWorld::ColumnBase::Display_ArmorType, CSMWorld::Columns::ColumnId_ArmorType, false }, + { CSMWorld::ColumnBase::Display_ClothingType, CSMWorld::Columns::ColumnId_ClothingType, false }, + { CSMWorld::ColumnBase::Display_CreatureType, CSMWorld::Columns::ColumnId_CreatureType, false }, + { CSMWorld::ColumnBase::Display_WeaponType, CSMWorld::Columns::ColumnId_WeaponType, false } + }; + + for (std::size_t i=0; iadd (sMapping[i].mDisplay, new CSVWorld::EnumDelegateFactory ( + CSMWorld::Columns::getEnums (sMapping[i].mColumnId), sMapping[i].mAllowNone)); connect (&CSMSettings::UserSettings::instance(), SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)), - this, SLOT (slotUpdateEditorSetting (const QString &, const QString &))); + this, SLOT (slotUpdateEditorSetting (const QString &, const QString &))); } CSVDoc::ViewManager::~ViewManager() @@ -159,6 +114,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) connect (view, SIGNAL (newDocumentRequest ()), this, SIGNAL (newDocumentRequest())); connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest())); + connect (view, SIGNAL (editSettingsRequest()), this, SIGNAL (editSettingsRequest())); updateIndices(); diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 1f4dcd51b..1f4efbd2e 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -61,6 +61,8 @@ namespace CSVDoc void closeMessageBox(); + void editSettingsRequest(); + public slots: void exitApplication (CSVDoc::View *view); 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/settings/usersettingsdialog.cpp b/apps/opencs/view/settings/usersettingsdialog.cpp index 21311c2da..e73e24dcb 100644 --- a/apps/opencs/view/settings/usersettingsdialog.cpp +++ b/apps/opencs/view/settings/usersettingsdialog.cpp @@ -1,5 +1,7 @@ #include "usersettingsdialog.hpp" +#include + #include #include #include @@ -9,14 +11,14 @@ #include #include #include - #include +#include +#include + +#include "../../model/settings/support.hpp" #include "datadisplayformatpage.hpp" #include "windowpage.hpp" - -#include "../../model/settings/support.hpp" -#include #include "settingwidget.hpp" CSVSettings::UserSettingsDialog::UserSettingsDialog(QMainWindow *parent) : @@ -29,7 +31,11 @@ CSVSettings::UserSettingsDialog::UserSettingsDialog(QMainWindow *parent) : connect (mListWidget, SIGNAL (currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this, - SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*))); + SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*))); + + QRect scr = QApplication::desktop()->screenGeometry(); + QRect rect = geometry(); + move (scr.center().x() - rect.center().x(), scr.center().y() - rect.center().y()); } CSVSettings::UserSettingsDialog::~UserSettingsDialog() diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index dd194abe9..fc9b7ee3b 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -109,6 +109,18 @@ CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const char **names, bool all add (i, names[i]); } +CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const std::vector& names, + bool allowNone) +{ + if (allowNone) + add (-1, ""); + + int size = static_cast (names.size()); + + for (int i=0; i& names, bool allowNone = false); + /// \param allowNone Use value of -1 for "none selected" (empty string) + virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; ///< The ownership of the returned CommandDelegate is transferred to the caller. diff --git a/apps/opencs/view/world/recordstatusdelegate.cpp b/apps/opencs/view/world/recordstatusdelegate.cpp index a0ffd3063..8085ec7be 100644 --- a/apps/opencs/view/world/recordstatusdelegate.cpp +++ b/apps/opencs/view/world/recordstatusdelegate.cpp @@ -1,8 +1,11 @@ #include "recordstatusdelegate.hpp" + #include #include #include + #include "../../model/settings/usersettings.hpp" +#include "../../model/world/columns.hpp" CSVWorld::RecordStatusDelegate::RecordStatusDelegate(const ValueList& values, const IconList & icons, @@ -37,9 +40,14 @@ bool CSVWorld::RecordStatusDelegate::updateEditorSetting (const QString &setting CSVWorld::RecordStatusDelegateFactory::RecordStatusDelegateFactory() { - DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_BaseOnly, "Base", ":./base.png"); - DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_Deleted, "Deleted", ":./removed.png"); - DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_Erased, "Deleted", ":./removed.png"); - DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_Modified, "Modified", ":./modified.png"); - DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_ModifiedOnly, "Added", ":./added.png"); + std::vector enums = + CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification); + + static const char *sIcons[] = + { + ":./base.png", ":./modified.png", ":./added.png", ":./removed.png", ":./removed.png", 0 + }; + + for (int i=0; sIcons[i]; ++i) + add (i, enums.at (i).c_str(), sIcons[i]); } diff --git a/apps/opencs/view/world/refidtypedelegate.cpp b/apps/opencs/view/world/refidtypedelegate.cpp index bf3acbb20..7cffbf3dd 100755 --- a/apps/opencs/view/world/refidtypedelegate.cpp +++ b/apps/opencs/view/world/refidtypedelegate.cpp @@ -1,4 +1,5 @@ #include "refidtypedelegate.hpp" + #include "../../model/world/universalid.hpp" CSVWorld::RefIdTypeDelegate::RefIdTypeDelegate @@ -6,6 +7,26 @@ CSVWorld::RefIdTypeDelegate::RefIdTypeDelegate : DataDisplayDelegate (values, icons, undoStack, parent) {} +bool CSVWorld::RefIdTypeDelegate::updateEditorSetting (const QString &settingName, const QString &settingValue) +{ + if (settingName == "Referenceable ID Type Display") + { + if (settingValue == "Icon and Text") + mDisplayMode = Mode_IconAndText; + + else if (settingValue == "Icon Only") + mDisplayMode = Mode_IconOnly; + + else if (settingValue == "Text Only") + mDisplayMode = Mode_TextOnly; + + return true; + } + + return false; +} + + CSVWorld::RefIdTypeDelegateFactory::RefIdTypeDelegateFactory() { UidTypeList uIdList = buildUidTypeList(); @@ -39,22 +60,3 @@ CSVWorld::RefIdTypeDelegateFactory::UidTypeList CSVWorld::RefIdTypeDelegateFacto return list; } - -bool CSVWorld::RefIdTypeDelegate::updateEditorSetting (const QString &settingName, const QString &settingValue) -{ - if (settingName == "Referenceable ID Type Display") - { - if (settingValue == "Icon and Text") - mDisplayMode = Mode_IconAndText; - - else if (settingValue == "Icon Only") - mDisplayMode = Mode_IconOnly; - - else if (settingValue == "Text Only") - mDisplayMode = Mode_TextOnly; - - return true; - } - - return false; -} diff --git a/apps/opencs/view/world/refrecordtypedelegate.cpp b/apps/opencs/view/world/refrecordtypedelegate.cpp deleted file mode 100644 index 2bcb7ca50..000000000 --- a/apps/opencs/view/world/refrecordtypedelegate.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "refrecordtypedelegate.hpp" -#include "../../model/world/universalid.hpp" - -CSVWorld::RefRecordTypeDelegate::RefRecordTypeDelegate - (const std::vector > &values, QUndoStack& undoStack, QObject *parent) - : EnumDelegate (values, undoStack, parent) -{} - -CSVWorld::RefRecordTypeDelegateFactory::RefRecordTypeDelegateFactory() -{ - unsigned int argSize = CSMWorld::UniversalId::getIdArgSize(); - - for (unsigned int i = 0; i < argSize; i++) - { - std::pair idPair = CSMWorld::UniversalId::getIdArgPair(i); - - mValues.push_back (std::pair(idPair.first, QString::fromUtf8(idPair.second))); - } -} - -CSVWorld::CommandDelegate *CSVWorld::RefRecordTypeDelegateFactory::makeDelegate (QUndoStack& undoStack, - QObject *parent) const -{ - return new RefRecordTypeDelegate (mValues, undoStack, parent); -} diff --git a/apps/opencs/view/world/refrecordtypedelegate.hpp b/apps/opencs/view/world/refrecordtypedelegate.hpp deleted file mode 100644 index baec2cc2e..000000000 --- a/apps/opencs/view/world/refrecordtypedelegate.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef REFRECORDTYPEDELEGATE_HPP -#define REFRECORDTYPEDELEGATE_HPP - -#include "enumdelegate.hpp" -#include "util.hpp" - -namespace CSVWorld -{ - class RefRecordTypeDelegate : public EnumDelegate - { - public: - RefRecordTypeDelegate (const std::vector > &mValues, QUndoStack& undoStack, QObject *parent); - }; - - class RefRecordTypeDelegateFactory : public CommandDelegateFactory - { - - std::vector > mValues; - - public: - RefRecordTypeDelegateFactory(); - - virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; - ///< The ownership of the returned CommandDelegate is transferred to the caller. - }; -} -/* - class VarTypeDelegate : public EnumDelegate - { - private: - - virtual void addCommands (QAbstractItemModel *model, - const QModelIndex& index, int type) const; - - public: - - VarTypeDelegate (const std::vector >& values, - QUndoStack& undoStack, QObject *parent); - }; - - class VarTypeDelegateFactory : public CommandDelegateFactory - { - std::vector > mValues; - - public: - - VarTypeDelegateFactory (ESM::VarType type0 = ESM::VT_Unknown, - ESM::VarType type1 = ESM::VT_Unknown, ESM::VarType type2 = ESM::VT_Unknown, - ESM::VarType type3 = ESM::VT_Unknown); - - virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; - ///< The ownership of the returned CommandDelegate is transferred to the caller. - - void add (ESM::VarType type); - }; -*/ - -#endif // REFRECORDTYPEDELEGATE_HPP 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/opencs/view/world/vartypedelegate.cpp b/apps/opencs/view/world/vartypedelegate.cpp index 72cbaae42..15ce2dbaf 100644 --- a/apps/opencs/view/world/vartypedelegate.cpp +++ b/apps/opencs/view/world/vartypedelegate.cpp @@ -4,6 +4,7 @@ #include #include "../../model/world/commands.hpp" +#include "../../model/world/columns.hpp" void CSVWorld::VarTypeDelegate::addCommands (QAbstractItemModel *model, const QModelIndex& index, int type) const @@ -75,29 +76,11 @@ CSVWorld::CommandDelegate *CSVWorld::VarTypeDelegateFactory::makeDelegate (QUndo void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type) { - struct Name - { - ESM::VarType mType; - const char *mName; - }; + std::vector enums = + CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_ValueType); - static const Name sNames[] = - { - { ESM::VT_None, "empty" }, - { ESM::VT_Short, "short" }, - { ESM::VT_Int, "integer" }, - { ESM::VT_Long, "long" }, - { ESM::VT_Float, "float" }, - { ESM::VT_String, "string" }, - { ESM::VT_Unknown, 0 } // end marker - }; + if (type<0 && type>=enums.size()) + throw std::logic_error ("Unsupported variable type"); - for (int i=0; sNames[i].mName; ++i) - if (sNames[i].mType==type) - { - mValues.push_back (std::make_pair (type, sNames[i].mName)); - return; - } - - throw std::logic_error ("Unsupported variable type"); + mValues.push_back (std::make_pair (type, QString::fromUtf8 (enums[type].c_str()))); } 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/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 b8d0a8745..566d4bc50 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/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 6b43a36f6..d47a49c70 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -33,46 +33,48 @@ namespace MWMechanics bool AiTravel::execute (const MWWorld::Ptr& actor) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWBase::World *world = MWBase::Environment::get().getWorld(); ESM::Position pos = actor.getRefData().getPosition(); - bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; - const ESM::Pathgrid *pathgrid = - MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); + Movement &movement = actor.getClass().getMovementSettings(actor); + const ESM::Cell *cell = actor.getCell()->mCell; - if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) + MWWorld::Ptr player = world->getPlayer().getPlayer(); + if(cell->mData.mX != player.getCell()->mCell->mData.mX) { - int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); - //check if actor is near the border of an inactive cell. If so, disable aitravel. - if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / - 2.0 - 200)) + int sideX = sgn(cell->mData.mX - player.getCell()->mCell->mData.mX); + //check if actor is near the border of an inactive cell. If so, stop walking. + if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) > + sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f)) { - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - return true; + movement.mPosition[1] = 0; + return false; } } - if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + if(cell->mData.mY != player.getCell()->mCell->mData.mY) { - int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); - //check if actor is near the border of an inactive cell. If so, disable aitravel. - if(sideY * (pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / - 2.0 - 200)) + int sideY = sgn(cell->mData.mY - player.getCell()->mCell->mData.mY); + //check if actor is near the border of an inactive cell. If so, stop walking. + if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) > + sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f)) { - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - return true; + movement.mPosition[1] = 0; + return false; } } + const ESM::Pathgrid *pathgrid = world->getStore().get().search(*cell); + bool cellChange = cell->mData.mX != cellX || cell->mData.mY != cellY; if(!mPathFinder.isPathConstructed() || cellChange) { - cellX = actor.getCell()->mCell->mData.mX; - cellY = actor.getCell()->mCell->mData.mY; + cellX = cell->mData.mX; + cellY = cell->mData.mY; float xCell = 0; float yCell = 0; - if (actor.getCell()->mCell->isExterior()) + if(cell->isExterior()) { - xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; - yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; + xCell = cell->mData.mX * ESM::Land::REAL_SIZE; + yCell = cell->mData.mY * ESM::Land::REAL_SIZE; } ESM::Pathgrid::Point dest; @@ -90,13 +92,13 @@ namespace MWMechanics if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) { - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + movement.mPosition[1] = 0; return true; } float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); - MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; + world->rotateObject(actor, 0, 0, zAngle, false); + movement.mPosition[1] = 1; return false; } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index c4f32f5dc..96a41883b 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -65,10 +65,11 @@ namespace MWMechanics bool AiWander::execute (const MWWorld::Ptr& actor) { + MWBase::World *world = MWBase::Environment::get().getWorld(); if(mDuration) { // End package if duration is complete or mid-night hits: - MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + MWWorld::TimeStamp currentTime = world->getTimeStamp(); if(currentTime.getHour() >= mStartTime.getHour() + mDuration) { if(!mRepeat) @@ -96,8 +97,7 @@ namespace MWMechanics if(!mStoredAvailableNodes) { mStoredAvailableNodes = true; - mPathgrid = - MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); + mPathgrid = world->getStore().get().search(*actor.getCell()->mCell); mCellX = actor.getCell()->mCell->mData.mX; mCellY = actor.getCell()->mCell->mData.mY; @@ -150,37 +150,8 @@ namespace MWMechanics } } - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - bool cellChange = actor.getCell()->mCell->mData.mX != mCellX || actor.getCell()->mCell->mData.mY != mCellY; - - if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) - { - int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); - // Check if actor is near the border of an inactive cell. If so, disable AiWander. - // FIXME: This *should* pause the AiWander package instead of terminating it. - if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / - 2.0 - 200)) - { - stopWalking(actor); - return true; - } - } - - if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) - { - int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); - // Check if actor is near the border of an inactive cell. If so, disable AiWander. - // FIXME: This *should* pause the AiWander package instead of terminating it. - if(sideY * (pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / - 2.0 - 200)) - { - stopWalking(actor); - return true; - } - } - // Don't try to move if you are in a new cell (ie: positioncell command called) but still play idles. - if(mDistance && (cellChange || (mCellX != actor.getCell()->mCell->mData.mX || mCellY != actor.getCell()->mCell->mData.mY))) + if(mDistance && (mCellX != actor.getCell()->mCell->mData.mX || mCellY != actor.getCell()->mCell->mData.mY)) mDistance = 0; if(mChooseAction) @@ -207,7 +178,7 @@ namespace MWMechanics else { // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: - MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + MWWorld::TimeStamp currentTime = world->getTimeStamp(); mStartTime = currentTime; playIdle(actor, mPlayedIdle); mChooseAction = false; @@ -264,18 +235,10 @@ namespace MWMechanics if(mWalking) { float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); - MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle,false); + world->rotateObject(actor, 0, 0, zAngle, false); MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; - // Unclog path nodes by allowing the NPC to be a small distance away from the center. This way two NPCs can be - // at the same path node at the same time and both will complete instead of endlessly walking into eachother: - Ogre::Vector3 destNodePos(mCurrentNode.mX, mCurrentNode.mY, mCurrentNode.mZ); - Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos); - actorPos[0] = actorPos[0] - mXCell; - actorPos[1] = actorPos[1] - mYCell; - float distance = actorPos.squaredDistance(destNodePos); - - if(distance < 1200 || mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) + if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) { stopWalking(actor); mMoveNow = false; 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/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index da9d52e44..8ef0edab8 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -147,13 +147,13 @@ namespace MWMechanics mIsPathConstructed = false; } - void PathFinder::buildPath(ESM::Pathgrid::Point startPoint, ESM::Pathgrid::Point endPoint, - const ESM::Pathgrid* pathGrid, float xCell, float yCell, bool allowShortcuts) + void PathFinder::buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, + const ESM::Pathgrid *pathGrid, float xCell, float yCell, bool allowShortcuts) { if(allowShortcuts) { - if(MWBase::Environment::get().getWorld()->castRay(startPoint.mX, startPoint.mY, startPoint.mZ, endPoint.mX, endPoint.mY, - endPoint.mZ)) + if(MWBase::Environment::get().getWorld()->castRay(startPoint.mX, startPoint.mY, startPoint.mZ, + endPoint.mX, endPoint.mY, endPoint.mZ)) allowShortcuts = false; } @@ -184,14 +184,14 @@ namespace MWMechanics mIsPathConstructed = false; } - float PathFinder::getZAngleToNext(float x, float y) + float PathFinder::getZAngleToNext(float x, float y) const { // This should never happen (programmers should have an if statement checking mIsPathConstructed that prevents this call // if otherwise). if(mPath.empty()) return 0; - ESM::Pathgrid::Point nextPoint = *mPath.begin(); + const ESM::Pathgrid::Point &nextPoint = *mPath.begin(); float directionX = nextPoint.mX - x; float directionY = nextPoint.mY - y; float directionResult = sqrt(directionX * directionX + directionY * directionY); @@ -205,7 +205,7 @@ namespace MWMechanics return true; ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(distanceZCorrected(nextPoint, x, y, z) < 40) + if(distanceZCorrected(nextPoint, x, y, z) < 64) { mPath.pop_front(); if(mPath.empty()) @@ -217,15 +217,5 @@ namespace MWMechanics return false; } - - std::list PathFinder::getPath() - { - return mPath; - } - - bool PathFinder::isPathConstructed() - { - return mIsPathConstructed; - } } diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 1727c650f..35e0fa908 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -12,15 +12,18 @@ namespace MWMechanics PathFinder(); void clearPath(); - void buildPath(ESM::Pathgrid::Point startPoint, ESM::Pathgrid::Point endPoint, - const ESM::Pathgrid* pathGrid, float xCell = 0, float yCell = 0, bool allowShortcuts = 1); + void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, + const ESM::Pathgrid* pathGrid, float xCell = 0, float yCell = 0, + bool allowShortcuts = true); bool checkPathCompleted(float x, float y, float z); ///< \Returns true if the last point of the path has been reached. - float getZAngleToNext(float x, float y); + float getZAngleToNext(float x, float y) const; - std::list getPath(); - bool isPathConstructed(); + bool isPathConstructed() const + { + return mIsPathConstructed; + } private: std::list mPath; 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/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/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index c41484452..5f4128978 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -370,8 +370,8 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, playerdirection.y); // explore radius (squared) - const float sqrExploreRadius = (mInterior ? 0.01 : 0.09) * sFogOfWarResolution*sFogOfWarResolution; - const float exploreRadius = (mInterior ? 0.1 : 0.3) * sFogOfWarResolution; // explore radius from 0 to sFogOfWarResolution + const float exploreRadius = (mInterior ? 0.1 : 0.3) * (sFogOfWarResolution-1); // explore radius from 0 to sFogOfWarResolution-1 + const float sqrExploreRadius = Math::Sqr(exploreRadius); const float exploreRadiusUV = exploreRadius / sFogOfWarResolution; // explore radius from 0 to 1 (UV space) // change the affected fog of war textures (in a 3x3 grid around the player) @@ -406,11 +406,8 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni { for (int texU = 0; texU> 24); alpha = std::min( alpha, (uint8) (std::max(0.f, std::min(1.f, (sqrDist/sqrExploreRadius)))*255) ); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a7e35fa19..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); @@ -1018,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/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 8c557ee99..ee2b80f73 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -1037,7 +1037,6 @@ public: VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* window) : mState(NULL) , mSceneMgr(sceneMgr) - , mVideoMaterial(NULL) , mRectangle(NULL) , mNode(NULL) , mAllowSkipping(false) 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/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 9d111a525..c6768f5fd 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -80,7 +80,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end() bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) { /// \todo add current enchantment charge here when it is implemented - if ( ptr1.getCellRef().mRefID == ptr2.getCellRef().mRefID + if ( Misc::StringUtils::ciEqual(ptr1.getCellRef().mRefID, ptr2.getCellRef().mRefID) && MWWorld::Class::get(ptr1).getScript(ptr1) == "" // item with a script never stacks && MWWorld::Class::get(ptr1).getEnchantment(ptr1) == "" // item with enchantment never stacks (we could revisit this later, but for now it makes selecting items in the spell window much easier) && ptr1.getCellRef().mOwner == ptr2.getCellRef().mOwner 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/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 5e293a292..724972600 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) diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index cdf8bc74b..682010340 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -11,14 +11,15 @@ if (GTEST_FOUND AND GMOCK_FOUND) include_directories(${GMOCK_INCLUDE_DIRS}) file(GLOB UNITTEST_SRC_FILES - components/misc/*.cpp + components/misc/test_*.cpp + components/file_finder/test_*.cpp ) source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) add_executable(openmw_test_suite openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) - target_link_libraries(openmw_test_suite ${GMOCK_BOTH_LIBRARIES} ${GTEST_BOTH_LIBRARIES}) + target_link_libraries(openmw_test_suite ${GMOCK_BOTH_LIBRARIES} ${GTEST_BOTH_LIBRARIES} components) # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) target_link_libraries(openmw_test_suite ${CMAKE_THREAD_LIBS_INIT}) diff --git a/apps/openmw_test_suite/components/file_finder/test_filefinder.cpp b/apps/openmw_test_suite/components/file_finder/test_filefinder.cpp new file mode 100644 index 000000000..2d151988b --- /dev/null +++ b/apps/openmw_test_suite/components/file_finder/test_filefinder.cpp @@ -0,0 +1,66 @@ +#include +#include +#include "components/file_finder/file_finder.hpp" + +struct FileFinderTest : public ::testing::Test +{ + protected: + FileFinderTest() + : mTestDir("./filefinder_test_dir/") + , mTestFile("test.txt") + , mTestFileUppercase("TEST.TXT") + , mTestFileNotFound("foobarbaz.txt") + { + } + + virtual void SetUp() + { + boost::filesystem::create_directory(boost::filesystem::path(mTestDir)); + + std::ofstream ofs(std::string(mTestDir + mTestFile).c_str(), std::ofstream::out); + ofs << std::endl; + ofs.close(); + } + + virtual void TearDown() + { + boost::filesystem::remove_all(boost::filesystem::path(mTestDir)); + } + + std::string mTestDir; + std::string mTestFile; + std::string mTestFileUppercase; + std::string mTestFileNotFound; +}; + +TEST_F(FileFinderTest, FileFinder_has_file) +{ + FileFinder::FileFinder fileFinder(mTestDir); + ASSERT_TRUE(fileFinder.has(mTestFile)); + ASSERT_TRUE(fileFinder.has(mTestFileUppercase)); + ASSERT_TRUE(fileFinder.lookup(mTestFile) == std::string(mTestDir + mTestFile)); + ASSERT_TRUE(fileFinder.lookup(mTestFileUppercase) == std::string(mTestDir + mTestFile)); +} + +TEST_F(FileFinderTest, FileFinder_does_not_have_file) +{ + FileFinder::FileFinder fileFinder(mTestDir); + ASSERT_FALSE(fileFinder.has(mTestFileNotFound)); + ASSERT_TRUE(fileFinder.lookup(mTestFileNotFound).empty()); +} + +TEST_F(FileFinderTest, FileFinderStrict_has_file) +{ + FileFinder::FileFinderStrict fileFinder(mTestDir); + ASSERT_TRUE(fileFinder.has(mTestFile)); + ASSERT_FALSE(fileFinder.has(mTestFileUppercase)); + ASSERT_TRUE(fileFinder.lookup(mTestFile) == std::string(mTestDir + mTestFile)); + ASSERT_FALSE(fileFinder.lookup(mTestFileUppercase) == std::string(mTestDir + mTestFile)); +} + +TEST_F(FileFinderTest, FileFinderStrict_does_not_have_file) +{ + FileFinder::FileFinderStrict fileFinder(mTestDir); + ASSERT_FALSE(fileFinder.has(mTestFileNotFound)); + ASSERT_TRUE(fileFinder.lookup(mTestFileNotFound).empty()); +} diff --git a/apps/openmw_test_suite/components/file_finder/test_search.cpp b/apps/openmw_test_suite/components/file_finder/test_search.cpp new file mode 100644 index 000000000..63745b625 --- /dev/null +++ b/apps/openmw_test_suite/components/file_finder/test_search.cpp @@ -0,0 +1,74 @@ +#include +#include +#include + +#include "components/file_finder/search.hpp" + +struct SearchTest : public ::testing::Test +{ + protected: + SearchTest() + : mTestDir("./search_test_dir/") + { + } + + virtual void SetUp() + { + boost::filesystem::create_directory(boost::filesystem::path(mTestDir)); + + std::ofstream ofs(std::string(mTestDir + "test2.txt").c_str(), std::ofstream::out); + ofs << std::endl; + ofs.close(); + } + + virtual void TearDown() + { + boost::filesystem::remove_all(boost::filesystem::path(mTestDir)); + } + + std::string mTestDir; +}; + +TEST_F(SearchTest, file_not_found) +{ + struct Result : public FileFinder::ReturnPath + { + Result(const boost::filesystem::path& expectedPath) + : mExpectedPath(expectedPath) + { + } + + void add(const boost::filesystem::path& p) + { + ASSERT_FALSE(p == mExpectedPath); + } + + private: + boost::filesystem::path mExpectedPath; + + } r(boost::filesystem::path(mTestDir + "test.txt")); + + FileFinder::find(mTestDir, r, false); +} + +TEST_F(SearchTest, file_found) +{ + struct Result : public FileFinder::ReturnPath + { + Result(const boost::filesystem::path& expectedPath) + : mExpectedPath(expectedPath) + { + } + + void add(const boost::filesystem::path& p) + { + ASSERT_TRUE(p == mExpectedPath); + } + + private: + boost::filesystem::path mExpectedPath; + + } r(boost::filesystem::path(mTestDir + "test2.txt")); + + FileFinder::find(mTestDir, r, false); +} diff --git a/apps/openmw_test_suite/components/misc/test_slicearray.cpp b/apps/openmw_test_suite/components/misc/test_slicearray.cpp new file mode 100644 index 000000000..ab63e56c4 --- /dev/null +++ b/apps/openmw_test_suite/components/misc/test_slicearray.cpp @@ -0,0 +1,33 @@ +#include +#include "components/misc/slice_array.hpp" + +struct SliceArrayTest : public ::testing::Test +{ + protected: + virtual void SetUp() + { + } + + virtual void TearDown() + { + } +}; + +TEST_F(SliceArrayTest, hello_string) +{ + Misc::SString s("hello"); + ASSERT_EQ(sizeof("hello") - 1, s.length); + ASSERT_FALSE(s=="hel"); + ASSERT_FALSE(s=="hell"); + ASSERT_TRUE(s=="hello"); +} + +TEST_F(SliceArrayTest, othello_string_with_offset_2_and_size_4) +{ + Misc::SString s("othello" + 2, 4); + ASSERT_EQ(sizeof("hell") - 1, s.length); + ASSERT_FALSE(s=="hel"); + ASSERT_TRUE(s=="hell"); + ASSERT_FALSE(s=="hello"); +} + diff --git a/apps/openmw_test_suite/components/misc/test_stringops.cpp b/apps/openmw_test_suite/components/misc/test_stringops.cpp index b12584196..44587c445 100644 --- a/apps/openmw_test_suite/components/misc/test_stringops.cpp +++ b/apps/openmw_test_suite/components/misc/test_stringops.cpp @@ -1,7 +1,79 @@ #include +#include "components/misc/stringops.hpp" -TEST(simple_test, dummy) +struct StringOpsTest : public ::testing::Test { - EXPECT_EQ(true, true); + protected: + virtual void SetUp() + { + } + + virtual void TearDown() + { + } +}; + +TEST_F(StringOpsTest, begins_matching) +{ + ASSERT_TRUE(Misc::begins("abc", "a")); + ASSERT_TRUE(Misc::begins("abc", "ab")); + ASSERT_TRUE(Misc::begins("abc", "abc")); + ASSERT_TRUE(Misc::begins("abcd", "abc")); +} + +TEST_F(StringOpsTest, begins_not_matching) +{ + ASSERT_FALSE(Misc::begins("abc", "b")); + ASSERT_FALSE(Misc::begins("abc", "bc")); + ASSERT_FALSE(Misc::begins("abc", "bcd")); + ASSERT_FALSE(Misc::begins("abc", "abcd")); +} + +TEST_F(StringOpsTest, ibegins_matching) +{ + ASSERT_TRUE(Misc::ibegins("Abc", "a")); + ASSERT_TRUE(Misc::ibegins("aBc", "ab")); + ASSERT_TRUE(Misc::ibegins("abC", "abc")); + ASSERT_TRUE(Misc::ibegins("abcD", "abc")); +} + +TEST_F(StringOpsTest, ibegins_not_matching) +{ + ASSERT_FALSE(Misc::ibegins("abc", "b")); + ASSERT_FALSE(Misc::ibegins("abc", "bc")); + ASSERT_FALSE(Misc::ibegins("abc", "bcd")); + ASSERT_FALSE(Misc::ibegins("abc", "abcd")); +} + +TEST_F(StringOpsTest, ends_matching) +{ + ASSERT_TRUE(Misc::ends("abc", "c")); + ASSERT_TRUE(Misc::ends("abc", "bc")); + ASSERT_TRUE(Misc::ends("abc", "abc")); + ASSERT_TRUE(Misc::ends("abcd", "abcd")); +} + +TEST_F(StringOpsTest, ends_not_matching) +{ + ASSERT_FALSE(Misc::ends("abc", "b")); + ASSERT_FALSE(Misc::ends("abc", "ab")); + ASSERT_FALSE(Misc::ends("abc", "bcd")); + ASSERT_FALSE(Misc::ends("abc", "abcd")); +} + +TEST_F(StringOpsTest, iends_matching) +{ + ASSERT_TRUE(Misc::iends("Abc", "c")); + ASSERT_TRUE(Misc::iends("aBc", "bc")); + ASSERT_TRUE(Misc::iends("abC", "abc")); + ASSERT_TRUE(Misc::iends("abcD", "abcd")); +} + +TEST_F(StringOpsTest, iends_not_matching) +{ + ASSERT_FALSE(Misc::iends("abc", "b")); + ASSERT_FALSE(Misc::iends("abc", "ab")); + ASSERT_FALSE(Misc::iends("abc", "bcd")); + ASSERT_FALSE(Misc::iends("abc", "abcd")); } diff --git a/apps/openmw_test_suite/openmw_test_suite.cpp b/apps/openmw_test_suite/openmw_test_suite.cpp index 0a09b3028..81476325e 100644 --- a/apps/openmw_test_suite/openmw_test_suite.cpp +++ b/apps/openmw_test_suite/openmw_test_suite.cpp @@ -5,8 +5,8 @@ int main(int argc, char** argv) { // The following line causes Google Mock to throw an exception on failure, // which will be interpreted by your testing framework as a test failure. - ::testing::GTEST_FLAG(throw_on_failure) = true; + ::testing::GTEST_FLAG(throw_on_failure) = false; ::testing::InitGoogleMock(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} 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/esm/variant.hpp b/components/esm/variant.hpp index 8c5f3b3d4..2bba60a15 100644 --- a/components/esm/variant.hpp +++ b/components/esm/variant.hpp @@ -11,7 +11,7 @@ namespace ESM enum VarType { - VT_Unknown, + VT_Unknown = 0, VT_None, VT_Short, // stored as a float, kinda VT_Int, 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/credits.txt b/credits.txt index dd583a0ec..9a84c5327 100644 --- a/credits.txt +++ b/credits.txt @@ -43,6 +43,7 @@ lazydev Leon Saunders (emoose) Lukasz Gromanowski (lgro) Manuel Edelmann (vorenon) +Marc Bouvier (CramitDeFrog) Marcin Hulist (Gohan) Mark Siewert (mark76) Mateusz Kołaczek (PL_kolek) diff --git a/extern/sdl4ogre/cursormanager.hpp b/extern/sdl4ogre/cursormanager.hpp index 1f52eca73..f45c5cdc2 100644 --- a/extern/sdl4ogre/cursormanager.hpp +++ b/extern/sdl4ogre/cursormanager.hpp @@ -4,10 +4,8 @@ #include #include -namespace Ogre -{ - class TexturePtr; -} +#include +#include namespace SFO { 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/openmw_chargen_birth.layout b/files/mygui/openmw_chargen_birth.layout index e8d959ba2..b368a6407 100644 --- a/files/mygui/openmw_chargen_birth.layout +++ b/files/mygui/openmw_chargen_birth.layout @@ -1,11 +1,12 @@ - + + - + @@ -13,7 +14,7 @@ - + @@ -24,5 +25,6 @@ + diff --git a/files/mygui/openmw_chargen_class.layout b/files/mygui/openmw_chargen_class.layout index aac97870c..3c0348b66 100644 --- a/files/mygui/openmw_chargen_class.layout +++ b/files/mygui/openmw_chargen_class.layout @@ -1,7 +1,8 @@ - + + @@ -20,6 +21,7 @@ + @@ -32,6 +34,7 @@ + @@ -40,6 +43,7 @@ + @@ -51,6 +55,7 @@ + @@ -60,7 +65,7 @@ - + @@ -71,5 +76,6 @@ + diff --git a/files/mygui/openmw_chargen_class_description.layout b/files/mygui/openmw_chargen_class_description.layout index e003f22c1..eaf754697 100644 --- a/files/mygui/openmw_chargen_class_description.layout +++ b/files/mygui/openmw_chargen_class_description.layout @@ -17,6 +17,6 @@ - + diff --git a/files/mygui/openmw_chargen_create_class.layout b/files/mygui/openmw_chargen_create_class.layout index e9c4146a0..92382640b 100644 --- a/files/mygui/openmw_chargen_create_class.layout +++ b/files/mygui/openmw_chargen_create_class.layout @@ -1,13 +1,15 @@ - + - + + + @@ -19,6 +21,7 @@ + @@ -31,6 +34,7 @@ + @@ -39,6 +43,7 @@ + @@ -50,6 +55,7 @@ + @@ -59,7 +65,7 @@ - + @@ -73,6 +79,6 @@ - + diff --git a/files/mygui/openmw_chargen_review.layout b/files/mygui/openmw_chargen_review.layout index 408d4f471..5d18f4bff 100644 --- a/files/mygui/openmw_chargen_review.layout +++ b/files/mygui/openmw_chargen_review.layout @@ -1,9 +1,9 @@ - + - + @@ -17,27 +17,27 @@ - - - - + + + + - - - + + + - + - + @@ -46,57 +46,57 @@ - - + + - + - + - + - + - + - + - + @@ -105,13 +105,13 @@ - - - + + + - - + + 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_progress.skin.xml b/files/mygui/openmw_progress.skin.xml index aa994fea7..35114ffeb 100644 --- a/files/mygui/openmw_progress.skin.xml +++ b/files/mygui/openmw_progress.skin.xml @@ -58,10 +58,23 @@ - + + + + + + + + + + + + + + diff --git a/files/opencs/raster/GMST.png b/files/opencs/raster/GMST.png new file mode 100644 index 000000000..f24620288 Binary files /dev/null and b/files/opencs/raster/GMST.png differ diff --git a/files/opencs/raster/activator.png b/files/opencs/raster/activator.png index 0446af22c..32cc6f8a3 100644 Binary files a/files/opencs/raster/activator.png and b/files/opencs/raster/activator.png differ diff --git a/files/opencs/raster/attribute.png b/files/opencs/raster/attribute.png new file mode 100644 index 000000000..4aa5dc02e Binary files /dev/null and b/files/opencs/raster/attribute.png differ diff --git a/files/opencs/raster/body-part.png b/files/opencs/raster/body-part.png index 4aa5dc02e..823e43712 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/book.png b/files/opencs/raster/book.png index 3afa9e8aa..9d7669bd7 100644 Binary files a/files/opencs/raster/book.png and b/files/opencs/raster/book.png differ diff --git a/files/opencs/raster/filter.png b/files/opencs/raster/filter.png new file mode 100644 index 000000000..94a57ecd9 Binary files /dev/null and b/files/opencs/raster/filter.png differ diff --git a/files/opencs/raster/ingredient.png b/files/opencs/raster/ingredient.png index 6b36d008d..564a93047 100644 Binary files a/files/opencs/raster/ingredient.png and b/files/opencs/raster/ingredient.png differ diff --git a/files/opencs/raster/light.png b/files/opencs/raster/light.png index c606fcd98..2765ef1d3 100644 Binary files a/files/opencs/raster/light.png and b/files/opencs/raster/light.png differ diff --git a/files/opencs/raster/random.png b/files/opencs/raster/random.png new file mode 100644 index 000000000..2667630f5 Binary files /dev/null and b/files/opencs/raster/random.png differ diff --git a/files/opencs/raster/soundgen.png b/files/opencs/raster/soundgen.png index 70ae43a1d..222fc4c7f 100644 Binary files a/files/opencs/raster/soundgen.png and b/files/opencs/raster/soundgen.png differ diff --git a/files/opencs/raster/startup/big/configure.png b/files/opencs/raster/startup/big/configure.png new file mode 100644 index 000000000..f0be888a1 Binary files /dev/null and b/files/opencs/raster/startup/big/configure.png differ diff --git a/files/opencs/raster/startup/big/create-addon.png b/files/opencs/raster/startup/big/create-addon.png new file mode 100644 index 000000000..fa059264e Binary files /dev/null and b/files/opencs/raster/startup/big/create-addon.png differ diff --git a/files/opencs/raster/startup/big/edit-content.png b/files/opencs/raster/startup/big/edit-content.png new file mode 100644 index 000000000..dbb2602e5 Binary files /dev/null and b/files/opencs/raster/startup/big/edit-content.png differ diff --git a/files/opencs/raster/startup/big/new-game.png b/files/opencs/raster/startup/big/new-game.png new file mode 100644 index 000000000..5cec44417 Binary files /dev/null and b/files/opencs/raster/startup/big/new-game.png differ diff --git a/files/opencs/raster/startup/small/configure.png b/files/opencs/raster/startup/small/configure.png new file mode 100644 index 000000000..e91b7f773 Binary files /dev/null and b/files/opencs/raster/startup/small/configure.png differ diff --git a/files/opencs/raster/startup/small/create-addon.png b/files/opencs/raster/startup/small/create-addon.png new file mode 100644 index 000000000..64fd138be Binary files /dev/null and b/files/opencs/raster/startup/small/create-addon.png differ diff --git a/files/opencs/raster/startup/small/edit-content.png b/files/opencs/raster/startup/small/edit-content.png new file mode 100644 index 000000000..6297f1169 Binary files /dev/null and b/files/opencs/raster/startup/small/edit-content.png differ diff --git a/files/opencs/raster/startup/small/new-game.png b/files/opencs/raster/startup/small/new-game.png new file mode 100644 index 000000000..0d7d14c55 Binary files /dev/null and b/files/opencs/raster/startup/small/new-game.png differ diff --git a/files/opencs/raster/static.png b/files/opencs/raster/static.png index b53be12d9..aedf2d30e 100644 Binary files a/files/opencs/raster/static.png and b/files/opencs/raster/static.png differ diff --git a/files/opencs/resources.qrc b/files/opencs/resources.qrc index 321413763..56e25b2c1 100644 --- a/files/opencs/resources.qrc +++ b/files/opencs/resources.qrc @@ -25,5 +25,9 @@ repair.png static.png weapon.png + raster/startup/big/create-addon.png + raster/startup/big/new-game.png + raster/startup/big/edit-content.png + raster/startup/small/configure.png diff --git a/files/opencs/scalable/referenceable-record/.directory b/files/opencs/scalable/referenceable-record/.directory index c633c38a9..98e1b7f92 100644 --- a/files/opencs/scalable/referenceable-record/.directory +++ b/files/opencs/scalable/referenceable-record/.directory @@ -1,7 +1,7 @@ [Dolphin] GroupedSorting=true SortFoldersFirst=false -Timestamp=2013,8,11,16,50,43 +Timestamp=2013,8,25,18,35,16 Version=3 ViewMode=2 VisibleRoles=Compact_text,Compact_size diff --git a/files/opencs/scalable/referenceable-record/book2.svgz b/files/opencs/scalable/referenceable-record/book2.svgz new file mode 100644 index 000000000..4535a2fce Binary files /dev/null and b/files/opencs/scalable/referenceable-record/book2.svgz differ diff --git a/files/opencs/scalable/referenceable-record/miscellaneous.svg b/files/opencs/scalable/referenceable-record/miscellaneous.svg deleted file mode 100644 index 96522048c..000000000 --- a/files/opencs/scalable/referenceable-record/miscellaneous.svg +++ /dev/null @@ -1,965 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/startup/configure.svgz b/files/opencs/scalable/startup/configure.svgz new file mode 100644 index 000000000..1275ec53f Binary files /dev/null and b/files/opencs/scalable/startup/configure.svgz differ diff --git a/files/opencs/scalable/startup/create-addon.svgz b/files/opencs/scalable/startup/create-addon.svgz new file mode 100644 index 000000000..75425667b Binary files /dev/null and b/files/opencs/scalable/startup/create-addon.svgz differ diff --git a/files/opencs/scalable/startup/edit-content.svgz b/files/opencs/scalable/startup/edit-content.svgz new file mode 100644 index 000000000..049f1e813 Binary files /dev/null and b/files/opencs/scalable/startup/edit-content.svgz differ diff --git a/files/opencs/scalable/startup/new-game.svgz b/files/opencs/scalable/startup/new-game.svgz new file mode 100644 index 000000000..e81571911 Binary files /dev/null and b/files/opencs/scalable/startup/new-game.svgz differ diff --git a/files/openmw.cfg.local b/files/openmw.cfg.local index dd116e108..d6ca2d554 100644 --- a/files/openmw.cfg.local +++ b/files/openmw.cfg.local @@ -1,2 +1,5 @@ +data="?global?data" +data="?mw?Data Files" data=./data +data-local="?user?data" resources=./resources diff --git a/libs/openengine/bullet/BulletShapeLoader.cpp b/libs/openengine/bullet/BulletShapeLoader.cpp index 431d2b91b..5528924a9 100644 --- a/libs/openengine/bullet/BulletShapeLoader.cpp +++ b/libs/openengine/bullet/BulletShapeLoader.cpp @@ -104,6 +104,20 @@ BulletShapeManager::~BulletShapeManager() sThis = 0; } +#if (OGRE_VERSION >= ((1 << 16) | (9 << 8) | 0)) +BulletShapePtr BulletShapeManager::getByName(const Ogre::String& name, const Ogre::String& groupName) +{ + return getResourceByName(name, groupName).staticCast(); +} + +BulletShapePtr BulletShapeManager::create (const Ogre::String& name, const Ogre::String& group, + bool isManual, Ogre::ManualResourceLoader* loader, + const Ogre::NameValuePairList* createParams) +{ + return createResource(name,group,isManual,loader,createParams).staticCast(); +} +#endif + BulletShapePtr BulletShapeManager::load(const Ogre::String &name, const Ogre::String &group) { BulletShapePtr textf = getByName(name); diff --git a/libs/openengine/bullet/BulletShapeLoader.h b/libs/openengine/bullet/BulletShapeLoader.h index a6591010a..98cda859d 100644 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ b/libs/openengine/bullet/BulletShapeLoader.h @@ -48,6 +48,8 @@ public: /** * */ + +#if (OGRE_VERSION < ((1 << 16) | (9 << 8) | 0)) class BulletShapePtr : public Ogre::SharedPtr { public: @@ -91,9 +93,9 @@ public: return *this; } }; - - - +#else +typedef Ogre::SharedPtr BulletShapePtr; +#endif /** *Hold any BulletShape that was created by the ManualBulletShapeLoader. @@ -137,6 +139,19 @@ public: BulletShapeManager(); virtual ~BulletShapeManager(); + +#if (OGRE_VERSION >= ((1 << 16) | (9 << 8) | 0)) + /// Get a resource by name + /// @see ResourceManager::getByName + BulletShapePtr getByName(const Ogre::String& name, const Ogre::String& groupName = Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); + + /// Create a new shape + /// @see ResourceManager::createResource + BulletShapePtr create (const Ogre::String& name, const Ogre::String& group, + bool isManual = false, Ogre::ManualResourceLoader* loader = 0, + const Ogre::NameValuePairList* createParams = 0); +#endif + virtual BulletShapePtr load(const Ogre::String &name, const Ogre::String &group); static BulletShapeManager &getSingleton(); diff --git a/libs/openengine/ogre/lights.cpp b/libs/openengine/ogre/lights.cpp index 52aca6a70..348057b84 100644 --- a/libs/openengine/ogre/lights.cpp +++ b/libs/openengine/ogre/lights.cpp @@ -1,20 +1,11 @@ #include "lights.hpp" #include -#include + namespace OEngine { namespace Render { - -LightFunction::LightFunction(LightType type) - : ControllerFunction(true) - , mType(type) - , mPhase(Ogre::Math::RangeRandom(-500.0f, +500.0f)) - , mDirection(1.0f) -{ -} - Ogre::Real LightFunction::pulseAmplitude(Ogre::Real time) { return std::sin(time); @@ -97,13 +88,6 @@ Ogre::Real LightFunction::calculate(Ogre::Real value) return brightness; } - -LightValue::LightValue(Ogre::Light *light, const Ogre::ColourValue &color) - : mTarget(light) - , mColor(color) -{ -} - Ogre::Real LightValue::getValue() const { return 0.0f; diff --git a/libs/openengine/ogre/lights.hpp b/libs/openengine/ogre/lights.hpp index c63f16425..61d09a0e6 100644 --- a/libs/openengine/ogre/lights.hpp +++ b/libs/openengine/ogre/lights.hpp @@ -3,6 +3,7 @@ #include #include +#include /* * Controller classes to handle pulsing and flicker lights @@ -30,7 +31,14 @@ namespace Render { static Ogre::Real flickerFrequency(Ogre::Real phase); public: - LightFunction(LightType type); + // MSVC needs the constructor for a class inheriting a template to be defined in header + LightFunction(LightType type) + : ControllerFunction(true) + , mType(type) + , mPhase(Ogre::Math::RangeRandom(-500.0f, +500.0f)) + , mDirection(1.0f) + { + } virtual Ogre::Real calculate(Ogre::Real value); }; @@ -40,7 +48,12 @@ namespace Render { Ogre::ColourValue mColor; public: - LightValue(Ogre::Light *light, const Ogre::ColourValue &color); + // MSVC needs the constructor for a class inheriting a template to be defined in header + LightValue(Ogre::Light *light, const Ogre::ColourValue &color) + : mTarget(light) + , mColor(color) + { + } virtual Ogre::Real getValue() const; virtual void setValue(Ogre::Real value); 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 ); diff --git a/readme.txt b/readme.txt index d00a959a0..7865f8dba 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. -Version: 0.25.0 +Version: 0.26.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org @@ -71,17 +71,61 @@ Allowed options: --new-game [=arg(=1)] (=0) activate char gen/new game mechanics --fs-strict [=arg(=1)] (=0) strict file system handling (no case folding) --encoding arg (=win1252) Character encoding used in OpenMW game messages: - + win1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages - + win1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages - + win1252 - Western European (Latin) alphabet, used by default - + --fallback arg fallback values CHANGELOG +0.26.0 + +Bug #274: Inconsistencies in the terrain +Bug #557: Already-dead NPCs do not equip clothing/items. +Bug #592: Window resizing +Bug #612: [Tamriel Rebuilt] Missing terrain (South of Tel Oren) +Bug #664: Heart of lorkhan acts like a dead body (container) +Bug #767: Wonky ramp physics & water +Bug #780: Swimming out of water +Bug #792: Wrong ground alignment on actors when no clipping +Bug #796: Opening and closing door sound issue +Bug #797: No clipping hinders opening and closing of doors +Bug #799: sliders in enchanting window +Bug #838: Pressing key during startup procedure freezes the game +Bug #839: Combat/magic stances during character creation +Bug #843: [Tribunal] Dark Brotherhood assassin appears without equipment +Bug #844: Resting "until healed" option given even with full stats +Bug #846: Equipped torches are invisible. +Bug #847: Incorrect formula for autocalculated NPC initial health +Bug #850: Shealt weapon sound plays when leaving magic-ready stance +Bug #852: Some boots do not produce footstep sounds +Bug #860: FPS bar misalignment +Bug #861: Unable to print screen +Bug #863: No sneaking and jumping at the same time +Bug #866: Empty variables in [Movies] section of Morrowind.ini gets imported into OpenMW.cfg as blank fallback option and crashes game on start. +Bug #867: Dancing girls in "Suran, Desele's House of Earthly Delights" don't dance. +Bug #868: Idle animations are repeated +Bug #874: Underwater swimming close to the ground is jerky +Bug #875: Animation problem while swimming on the surface and looking up +Bug #876: Always a starting upper case letter in the inventory +Bug #878: Active spell effects don't update the layout properly when ended +Bug #891: Cell 24,-12 (Tamriel Rebuilt) crashes on load +Bug #896: New game sound issue +Feature #49: Melee Combat +Feature #71: Lycanthropy +Feature #393: Initialise MWMechanics::AiSequence from ESM::AIPackageList +Feature #622: Multiple positions for inventory window +Feature #627: Drowning +Feature #786: Allow the 'Activate' key to close the countdialog window +Feature #798: Morrowind installation via Launcher (Linux/Max OS only) +Feature #851: First/Third person transitions with mouse wheel +Task #689: change PhysicActor::enableCollisions +Task #707: Reorganise Compiler + 0.25.0 Bug #411: Launcher crash on OS X < 10.8